Django学习(三)——MVC架构

本文详细介绍了Django的MVC框架,包括Model、View和Template的职责与交互。讲解了Model用于数据处理,View处理数据逻辑并与用户交互,Template负责展示。文章还阐述了Django的MTV模式,强调了每个部分的作用,以及如何通过urls.py进行数据分派。此外,还提供了创建和操作数据库模型,以及在View和Template中处理数据的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第四章 Django的MVC框架

4.1 Django的MVC框架简介

MVC是一种软件工程设计方法,它把一个要创建的系统分成三部分,分别是Model数据模块,View视图模块以及Controller控制模块。

Model数据模块:包含系统中的数据内容,通常以数据库的形式来存储,如果这些内容有变动,就会通知View实时更改显示的内容,一些处理数据的程序逻辑也会放在这里。

View视图模块:创建和用户之间的界面,把用户的请求传送给Controller,并按照Controller的要求把来自Model的数据显示出来。

Controller控制模块:派发View传来的用户请求,并按照这些请求处理数据内容以及设置要显示的数据。

好处:大幅地降低系统的复杂性。

Django主要的架构形成了使用Model、Template和View三部分的搭配。这三部分分别对应网站的数据存储model.py、网站的模板文件组(一般放在templates文件夹下的html文件)以及控制如何处理数据程序逻辑的views.py,其中许多控制逻辑也被放在整个Django Framework中,(如urls.py的设置等)。

在此架构下,初学者可以这样看:使用templates来做每个网页的外观框架,送至templates中要被使用的数据尽量是可以直接显示的简单形式。
如果需要对变量进行更复杂的运算,那么这些工作应该放在view.py中完成。

在models.py中定义所有需要用到的数据格式,一般是以数据库的形式来存储的,定义后的Model数据类要把它import到views.py中

主要的操作流程为:用户在浏览器下达request,这个request会先被送到网站服务器中做分派的工作,这个分派的工作指定在urls.py中完成。每一个分派的工作都被设置成views.py中的函数,也就是主要处理数据的逻辑,在views.py中完成。因此所有在urls.py中指派的函数要在urls.py的前面import才行。

在Django MTV架构下的网站开发步骤

  • 需求分析,列出本次网站项目所要实现的目标,包括简单的草图,与功能方块图。
  • 数据库设计,网站中所有会用到的数据内容、格式、以及各个数据之间的关系。减少开始设计程序后修改Model的工作。
  • 了解网站的每一个界面,并设计网页模板(.html)文件
  • 生成项目,创建APP
  • 创建templates文件夹,并把所有网页模板(.html)文件都放在此文件夹
  • 创建static文件夹,并把所有静态文件(图像文件、CSS文件、.JS文件等)都都放在此文件夹中
  • 修改setting.py,把相关文件夹设置都加入,也把生成的app名称加入INSTALLEC_APPS序列中
  • 编辑models.py创建数据表格
  • 编辑views.py先import在models.py中创建的数据模型
  • 编辑admin.py把models.py中定义的数据模型加入,并使用admin.site.register注册新增的类,让admin界面可以处理数据库内容
  • 编辑views.py设计处理数据的相关模块,输入和输出都通过templates相关的模块操作获取来自于网页的输入数据,以及显示.html文件的网页内容
  • 编辑urls.py先import在views.py中定义的模块,创建网址和views.py中定义的模块的对应关系
  • 执行python manage.py makemigration; python manage.py migrate; python manage.py runserver测试网站

4.2 Model简介

首先创建项目:

django-admin startproject mysite
cd mysite/
python manage.py startapp myapp

Model是Django表示数据的模式,以Python的类为基础在models.py中设置数据项与数据格式。基本上每个类对应一个数据库中的数据表。因此,定义每个数据项时,除了数据项名称外,还要定义此项目的格式以及这张表格和其他表格相互之间的关系(即数据关联)。网站的其他数据就可以使用Python语句来操作这些数据内容,而不用关心实际使用的SQL指令。

例:

from django.db import models
class Post(models.Model)
    title = models.CharField(max_length=200)
    slug = models.CharField(max_length=200)
    body = models.TextField()
    pub_date = models.DateTimeField(default=timezone.now)

在参数中应该导入models.Model,然后就可以使用models.* 来指定数据表中的每一个字段的特征。

常用的数据字段类型:

  • CharField(max_length)——用来存储较短数据的字符串,通常使用于单行的文字数据
  • DateField(auto_now)——每次对象被存储时就自动加入当前日期。日期格式可用于datetime.date
  • TextField——长文字格式,一般用在HTML窗体的Textarea输入项目中

首次设置Model的内容要先执行python manage.py makemigrations以及python manage.py migrate

然后系统就会把我们设置的NewTable数据表建立到数据库中,默认是SQLite,也就是存在于同一文件夹下的db.sqlites文件。

会看到0001_initial.py以及__init__.py这两个文件。0001文件就是记录第一次Model设置的数据表内容,因为一开始只有一个设置,所以只有0001这个版本。Django偷偷帮我们加上了一个id字段,设置为主键,并自动增加了数值内容,以便它内部的数据管理。

在admin.py中创建数据表管理界面

在models.py中创建类之后,只要在admin.py中加入这个NewTable,就可以在/admin中管理这张表了(事先要createsuperuser创建管理员账号和密码)

先创建一个产品类(models.py):

class Product(models.Model):
    SIZES = (
        ('S', 'Smaill'),
        ('M', 'Medium'),
        ('L', 'Large'),
    )
    sku = models.CharField(max_length=5)
    name = models.CharField(max_length=20)
    price = models.PostitiveIntegerField()
    size = models.CharField(max_length=1, choices=SIZES)

上述代码,先创建一个名为SIZE的元组,其中每个元素也是一个元组,第一个项目是要被实际存储的内容,此例为’S’,’M’,’L’,后面那个项目是对应的说明,此例为’Smaill’等。编辑models.py后一定要执行migrate才行(如果中间修改过,就需要先执行makemigrations,这两个指令简单地看就是要求套用最新的数据表的新增或修改的内容)。执行:

python manage.py migrate

回到admin.py,加入这个新的类并注册:

from django.contrib import admin
from myapp.models import Product

admin.site.register(Product)

如何修改数据库

首先需要在models.py中修改,之后需要执行makemigrations以及migrate记录下这个修改操作。

这些操作都会被记录在myapp/migration文件夹下,分别是:

ls myapp/migrations/
0001_initial.py   0002_auto_20170815_0643.py   __init__.py
0001_initial.pyc  0002_auto_20170815_0643.pyc  __init__.pyc

注:0001是建立了Project这个数据表,0002是修改small的程序。

在Python Shell中操作数据库

在python中一般不使用SQL指令来存储数据,而是以ORM的方式来存取数据库里的内容。它以对象的的方式来看待每一条数据,可以解决底层数据库兼容的问题。如果把这些指令对应到实际每一种数据库的内部操作,就由元数据以及Django内部去处理,开发网站的文员不用去担心这个部分。

python manage.py shell
from myapp.models import Project
p = Product.objects.create(sku=0001,name='GrayBox',price=100,size='S')
p.save()

过程:python manage.py shell 是进入拥有此网站环境的Python Shell,一开始要导入在models.py中建立的Product数据表。通过Product.object.create指令创建一组数据,同时把这组数据交给一个变量(此例为p),然后通过p.save()把它真正存到数据表中。离开后,在admin界面中,即可查询到此记录。

使用Product.objects.all()函数可以取得所有数据(按顺序保存在一个数组中)操作过程:

allp = Product.objects.all()
allp[0]

在class Product中加入如下函数,解决显示不明确的项目标题:

def __unicode__(self):
    return self.name

这个函数是在这个类的实例被打印出来的时候会被调用,直接显示其中的name字段。

数据的查询与编辑

Django的ORM操作最重要的是找到数据项(记录),把它放到某个变量中,然后就可以针对这个变量做任何想要的操作,包括修改其中的内容,只要最后调用了save()函数,修改的内容,就会反映到数据库。

4.3 View简介

View是Django最重要的程序逻辑所在的地方,网站大部分程序设计都放在此。这里放了许多我们要操作的数据,以及安排哪些数据需要被显示出来的函数。在函数中把这些数据传送给网页服务器或交给Template的渲染器,再发送到网页服务器中。这些放在views.py中的函数,再由urls.py中的设计进行对应和派发。

要直接显示数据到网页,最简单的步骤是:先到urls.py设置一个网址的对应,然后在views.py中编写一个函数,通过HttpResponse传送出想要显示的数据。

如果想要建立一个简单显示个人信息的网页,这个网页希望放在/about路径中,那么可以在views.py中编写一个about函数,语句如下:

from django.http import HttpResponse
# Create your views here.

def about(request):
    html = '''
<!DOCTYPE html>
<html>
<head><title>About Myself</title></head>
<body>
<h2>Min-Huang Ho</h2>
<hr>
<p>
Hi, I am Min-Huang HO. Nice to meet you!
</p>
</body>
</html>
'''
    return HttpResponse(html)

在views.py最前面,导入用来处理HTTP协议的模块,about()函数需要接收request参数。Python中三引号来定义html字符串,这样可以使用多行的HTML程序代码,排版上较方便。然后通过HttpResponse(html)传送出去。

然后修改urls.py来设置:

from django.conf.urls import include, url
from django.contrib import admin
from myapp.views import about

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^about/', about)
]

在views.py中显示查询数据列表

下面要在views.py中查询models.py中定义且已存储的数据。并显示在用户端的网页上。

在views.py中要建立一个函数,此例中为listing

#_*_ coding: utf-8 _*_
from django.shortcuts import render
from django.http import HttpResponse
from myapp.models import Product
# Create your views here.

def listing(request):
    html = '''
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>手机列表</title>
</head>
<body>
<h2>以下是本店手机销售列表</h2>
<hr>
<table width=400 border=1 bgcolor='#ccffcc'>
{}
</table>
</body>
</html>
'''

    products = Product.objects.all()
    tags = '<tr><td>产品</td><td>售价</td><td>型号</td></tr>'
    for p in products:
    tags = tags + '<tr><td>{}</td>'.format(p.name)
    tags = tags + '<td>{}</td>'.format(p.price)
    tags = tags + '<td>{}</td></tr>'.format(p.size)

    return HttpResponse(html.format(tags))

这里设计了一个<table>{}</table>设计,即从数据库’捞’数据,表格中的实际内容是在后面的程序代码中准备好以后,再以format函数把它安插在”{}”中,因此要先放一个大括号留着后面使用。

Product.objects.all()找出所有数据项并存放在peoducts变量红,而以tags变量来把HTML表格的标记和数据排版在一起,在函数最后使用html.format(tags)把表格的内容放在html字符串正确的地方,再由HttpResponse函数返回给网页服务器。

在urls.py中也要加入listing函数,以及import包。

from django.conf.urls import include, url
from django.contrib import admin
from myapp.views import about,listing

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^about/', about),
    url(r'^list/', listing),
]

访问0.0.0.0:8000/list 即可显示数据列表

网址栏参数处理的方式

如果要显示某个指定的机型,应该如何处理?

  • 第一点:是在views.py中设置的处理函数必须能够接收参数,根据参数寻找所需的数据并加以显示
  • 第二点:在urls.py中的网址对应出也要有能力传送参数到views.py中

首先设计一个处理函数disp_detail()

#_*_ coding: utf-8 _*_
from django.shortcuts import render
from django.http import HttpResponse,Http404
from myapp.models import Product
# Create your views here.

def disp_detail(request, sku):
    html = '''
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>{}</title>
</head>
<body>
<h2>{}</h2>
<hr>
<table width=400 border=1 bgcolor='#ccffcc'>
{}
</table>
<a href='/list'>返回列表</a>
</body>
</html>
'''
    try:
    p = Product.objects.get(sku=sku)
    except Product.DoesNotExist:
    raise Http404('找不到指定的产品编号')
    tags = '<tr><td>产品编号</td><td>{}</td></tr>'.format(p.sku)
    tags = tags + '<tr><td>{}</td>'.format(p.name)
    tags = tags + '<td>{}</td>'.format(p.price)
    tags = tags + '<td>{}</td></tr>'.format(p.size)
    return HttpResponse(html.format(p.name, p.name, tags))

首先在import的地方多导入了Http404,用来产生标准的”404找不到网页”
的响应,当发生找不到数据的情况时(函数中的except Product.DoesNotExist例外处理),只要使用raise Http404(‘要显示的信息’)就可以了。

另外在disp_detail(request,sku)后面多加一个传送进来的参数sku(数据表中的产品编号),通过这个sku号,使用Product.objects.get(sku=sku)来搜索数据。如果找不到就产生一个Http404的例外;如果找到了。就把数据放在P变量中,然后可以在后面取出应用。

更改urls.py:

from django.conf.urls import include, url
from django.contrib import admin
from myapp.views import about, listing, disp_detail

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^about/', about),
    url(r'^list/([0-9a-zA-Z]+)/$', disp_detail),
    url(r'^list/', listing),
]

访问 0.0.0.0:8000/list/2/

4.4 Template 简介

要建立专业网站,一定要使用高级功能的模板网页显示方法。也就是把HTML文件另外存成模板文件,然后把要显示在网页的数据另外以变量的方式传送给渲染器,让渲染器根据变量的内容和指定的模板文件进行整合,再把结果输出给网页服务器。

创建template文件夹和文件

首先在当前的项目目录下创建一个名为templates的文件夹,它的等级与manage.py属同一层。接着在settings.py中设置TEMPLATES,如下:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],

接着在templates文件夹中创建一个about.html文件,如下:

<!-- about.html -->
<!DOCTYPE html>
<html>
<head>
    <meat charset='utf-8'>
    <title>About Myself</title>
</head>
<body>
<h2>Zhe-Rui Chang</h2>
<hr>
<p>
Hi, I am Zhe-Rui Chang.Nice to meet you!
</p>
<em>今日佳句:{{ quote }}</em>
</body>
</html>

这里把quote变量放在”{{}}”中,即可在网页打开时显示出来。

传送变量到template文件中

在views.py前面要使用import get_template模块,还用到了随机数功能:

#_*_ coding: utf-8 _*_
from django.shortcuts import render
from django.http import HttpResponse,Http404
from myapp.models import Product
from django.template.loader import get_template
import random

def about(request):
    template = get_template('about.html')
    quotes = ['今日事,今日毕','要收获,先付出','知识就是力量','一个人的个性就是他的命运']
    html = template.render({'quote':random.choice(quotes)})
    return HttpResponse(html)

在程序中,首先使用get_template函数取得about.html文件的执行实例,然后用template.render()方法函数执行网页显示的工作。此例中,要显示quote变量,因此会在render函数中传送“{‘quote’:random.choice(quotes)}”参数进去,因此在about.html中就可以顺利取得quote变量,并把它显示出来。渲染后的网页数据放在html变量中,再使用HttpResponse函数把它传给网页服务器。

同样的方法也可以用到disp_detail函数中,创建一个disp.html

<!-- disp.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>{{product.name}}</title>
</head>
<body>
<h2>{{product.name}}</h2>
<hr>
<table width=400 border=1 bgcolor='#ccffcc'>
<tr><td>产品编号</td><td>{{product.sku}}</td></tr>
<tr><td>产品名称</td><td>{{product.name}}</td></tr>
<tr><td>售价</td><td>{{product.price}}</td></tr>
<tr><td>产品型号</td><td>{{product.size}}</td></tr>
</table>
<a href='/list'>返回列表</a>
</body>
</html>

view.py:

#_*_ coding: utf-8 _*_
from django.shortcuts import render
from django.http import HttpResponse,Http404
from myapp.models import Product
from django.template.loader import get_template
import random
# Create your views here.

def disp_detail(request, sku):
    try:
    p = Product.objects.get(sku=sku)
    except Product.DoesNotExist:
    raise Http404('找不到指定的产品编号')
    template = get_template('disp.html')
    html = template.render({'product':p})
    return HttpResponse(html)

render在渲染时会把变量中的内容当作一般的字符来处理,而不是HTML标记,因此不应该在view.py中处理网页呈现的问题,应该回归到template文件中才对。因此,我们要做的是把变量传到disp.html中,然后在disp.html中以template的命令来处理。

在template中处理列表变量

view.py

def listing(request): 
    products = Product.objects.all()
    template = get_template('list.html')
    html = template.render({'products':products})
    return HttpResponse(html)

把找到的products列表变量直接放到template中就可以了,真正显示内容的格式则放在list.html中执行。

list.html






手机列表


以下是销售中的手机列表






{% for p in products %}





{% endfor %}
产品名售价型号
{{p.name}}{{p.price}}{{p.size}}


for循环时,会逐一把product列表中的每一个元素取出来放在p中。

4.5 最终版本

为网站加入首页,index.html(之前在about.html的数据改至此)

index.html

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <meat charset='utf-8'>
    <title>Welcome to mynewsite</title>
</head>
<body>
<h2>Welcome to mynewsite</h2>
<hr>
<ul>
    <li><a href='/list'>手机列表</a></li>
    <li><a href='/about'>关于我</a></li>
</ul>
<hr>
<em>今日佳句:{{ quote }}</em>
</body>
</html>

urls.py

from django.conf.urls import include, url
from django.contrib import admin
from myapp.views import about, listing, disp_detail, index

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^$', index),
    url(r'^about/', about),
    url(r'^list/([0-9a-zA-Z]+)/$', disp_detail),
    url(r'^list/$', listing),
]

about.html 比之前多加一个回到首页的链接:

<!-- about.html -->
<!DOCTYPE html>
<html>
<head>
    <meat charset='utf-8'>
    <title>About Myself</title>
</head>
<body>
<h2>Zhe-Rui Chang</h2>
<hr>
<p>
Hi, I am Zhe-Rui Chang.Nice to meet you!
</p>
<hr>
<a href='/'>回首页<a>
</body>
</html>

显示所有手机列表list.html 多加一个对应每个产品的链接

<!-- list.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>手机列表</title>
</head>
<body>
<h2>以下是销售中的手机列表</h2>
<hr>
<table width=400 boder=1 bgcolor='#ccffcc'>
    <tr><td>产品名</td><td>售价</td><td>型号</td></tr>
{% for p in products %}
    <tr>
    <td>
        <a href='/list/{{p.sku}}/'>{{p.name}}<a>
    </td>
    <td>{{p.price}}</td>
    <td>{{p.size}}</td>
    </tr>
{% endfor %}
</table>
<hr>
<a href='/'>回首页<a>
</body>
</html>

显示单一产品详情的disp.html

<!-- disp.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>{{product.name}}</title>
</head>
<body>
<h2>{{product.name}}</h2>
<hr>
<table width=400 border=1 bgcolor='#ccffcc'>
<tr><td>产品编号</td><td>{{product.sku}}</td></tr>
<tr><td>产品名称</td><td>{{product.name}}</td></tr>
<tr><td>售价</td><td>{{product.price}}</td></tr>
<tr><td>产品型号</td><td>{{product.size}}</td></tr>
</table>
<a href='/list'>返回列表</a>
</body>
</html>

使用了template网页显示的技巧后,view.py中各个函数就变得比较简单了。

#_*_ coding: utf-8 _*_
from django.shortcuts import render
from django.http import HttpResponse,Http404
from myapp.models import Product
from django.template.loader import get_template
import random
# Create your views here.

def disp_detail(request, sku):
    try:
    p = Product.objects.get(sku=sku)
    except Product.DoesNotExist:
    raise Http404('找不到指定的产品编号')
    template = get_template('disp.html')
    html = template.render({'product':p})
    return HttpResponse(html)

def listing(request): 
    products = Product.objects.all()
    template = get_template('list.html')
    html = template.render({'products':products})
    return HttpResponse(html)

def index(request):
    template = get_template('index.html')
    quotes = ['今日事,今日毕','要收获,先付出','知识就是力量','一个人的个性就是他的命运']
    html = template.render({'quote':random.choice(quotes)})
    return HttpResponse(html)

def about(request):
    template = get_template('about.html')
    html = template.render()
    return HttpResponse(html)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值