创建数据驱动页面的流程

在 Django 中创建数据驱动页面主要分为 5 步:
➊ 在 views.py 文件中导入想使用的模型。
➋ 在视图函数中查询模型,获取想呈现的数据。
➌ 把从模型获取的数据传给模板上下文。
➍ 创建或修改模板,显示上下文中的数据。
➎ 把 URL 映射到视图上(如果还未做的话)。
以上就是在 Django 框架中把模型、视图和模板连接在一起的步骤。

在首页显示分类

客户对主页的要求之一是显示最受欢迎的 5 个分类。下面根据上述步骤实现这一要求。
导入所需的模型
首先完成第一步。打开 rango/views.py 文件,在顶部其他导入语句之后从 Rango 应用的 models.py
文件中导入 Category 模型:

# 导入 Category 模型
from rango.models import Category

修改 index 视图
下面完成第 2 步和第 3 步。我们要修改主页的视图函数,即 index() 。根据下述代码修改。

def index(request):# 查询数据库,获取目前存储的所有分类# 按点赞次数倒序排列分类# 获取前 5 个分类(如果分类数少于 5 个,那就获取全部)# 把分类列表放入 context_dict 字典# 稍后传给模板引擎category_list = Category.objects.order_by('-likes')[:5]context_dict = {'categories': category_list}# 渲染响应,发给客户端return render(request, 'rango/index.html', context_dict)

这里的 Category.objects.order_by('-likes')[:5] 从 Category 模型中查询最受欢迎的前 5 个分
类。 order_by() 方法的作用是排序,这里我们根据 likes 字段的值倒序排列。 -likes 中的 - 号表
示倒序(如果没有 - 号,返回的结果是升序排列的)。因为我们想获得一个分类对象列表,所以
使用 Python 的列表运算符从列表中获取前 5 个对象( [:5] ),返回一个 Category 对象子集。
查询结束后,把列表的引用( category_list 变量)传给 context_dict 字典。最后把这个字典作
为模板上下文传给 render() 函数。

修改 index 模板
更新视图之后,接下来要做第 4 步,更新项目根目录中 templates 目录里的 rango/index.html 模
板。根据下述代码片段修改模板中的 HTML。

<!DOCTYPE html>
{% load staticfiles %}
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Rango says...</h1>
<div>hey there partner!</div>
<div>
{% if categories %}
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no categories present.</strong>
{% endif %}
</div>
<div>
<a href="/rango/about/">About Rango</a><br />
<img src="{% static "images/rango.jpg" %}" alt="Picture of Rango" />
</div>
</body>
</html>

这里,我们使用 Django 模板语言提供的 if 和 for 控制语句呈现数据。在页面的 <body> 元素中,
我们判断 categories (包含分类列表的上下文变量)中有没有分类( {% if categories %} )。
如果有分类,构建一个 HTML 无序列表( <ul> 标签)。 for 循环迭代分类列表( {% for category
in categories %} ),在列表项目( <li> 标签)中输出各分类的名称( {{ category.name }} )。
如果没有分类,显示一个消息,指明没有分类。
从上述代码片段可以看出,Django 模板语言中的命令放在 {% 和 %} 之间,而变量放在 {{ 和 }} 之
间。

创建详情页面
根据设计要求,每个分类还有对应的详情页面。这里有些挑战要克服。我们要定义一个参数化视
图,而且 URL 模式中要编码分类名称。

URL 设计和映射
先解决 URL 问题。我们可以在 URL 中使用分类的唯一 ID,例如 /rango/category/1/ 或 /rango/cate-
gory/2/,其中的数字 1 和 2 是分类的唯一 ID。可是从 ID 上看不出到底是哪个分类。
更好的方法是在 URL 中使用分类的名称。例如,可以通过 URL /rango/category/python/ 访问与
Python 相关的网页列表。这样的 URL 简单、可读性高,而且具有一定的语义。如果采用这种形
式,还要处理有多个单词的分类名,例如“Other Frameworks”。

为此,我们要使用 Django 提供的 slugify 函数。

为分类添加 slug 字段
为了得到可读性高的 URL,我们要为 Category 模型添加一个别名(slug)字段。然后使用 Django
提供的 slugify 函数把空白替换为连字符,例如 "how do i create a slug in django" 将变成
"how-do-i-create-a-slug-in-django" 。

◆ 不安全的 URL ◆

URL 中虽然可以有空格,但是却会导致安全问题。详情参见因特网工程任务组(Internet En-
gineering Task Force)发布的 URL RFC。

此外,还要覆盖 Category 模型的 save() 方法,调用 slugify() 函数更新 slug 字段。注意,只要
分类名称变了,别名就随之改变。参照下述代码片段更新模型,别忘了导入 slugify() 函数。

from django.template.defaultfilters import slugify
...
class Category(models.Model):name = models.CharField(max_length=128, unique=True)views = models.IntegerField(default=0)likes = models.IntegerField(default=0)slug = models.SlugField()def save(self, *args, **kwargs):self.slug = slugify(self.name)super(Category, self).save(*args, **kwargs)class Meta:verbose_name_plural = 'categories'def __str__(self):return self.name

更新模型之后,接下来要把变动应用到数据库上。然而,数据库中已经有数据了,因此我们必须
考虑改动产生的影响。其实我们想做的很简单,就是从分类名称中得到别名(此项操作在初次保
存记录时执行)。通过迁移工具能把 slug 字段添加到数据库中,而且可以为该字段指定默认值。
可是,每个分类的别名应该是不同的。因此,我们将先执行迁移,然后重新运行填充脚本。之所
以这么做,是因为填充脚本会在分类上调用 save() 方法,从而触发上面实现的 save() 方法,更

新各分类的别名。
执行下述命令,执行迁移:

$ python manage.py makemigrations rango
$ python manage.py migrate

我们没有为 slug 字段指定默认值,而且数据库中有数据,因此 migrate 命令会给你两个选择。选
择提供默认值的选项,输入一个空字符串(两个引号,即 '' )。然后运行填充脚本,更新 slug
字段。

$ python populate_rango.py

执行 python manage.py runserver 命令,启动 Django 开发服务器,在管理界面中查看模型中的数
据。
如果此时通过管理界面添加分类,可能会遇到一两个问题。
➊ 假设要添加的分类名是“Python User Groups”。保存时 Django 会阻止你,让你填写别名。虽
然可以自己动手输入“python-user-groups”,但是这样容易出错。如果能自动生成别名就好
了。
➋ 如果有个分类名为“Django”,还有个名为“django”,又会遇到一个问题。因为 slugify() 函
数生成的别名是小写形式,所以无法区分别名“django”对应于哪个分类。
第一个问题的解决方法有两个。其一,更新模型,把 slug 字段设为允许空值:
slug = models.SlugField(blank=True)
其二,定制管理界面,在输入分类名称时自动填写别名。请参照下述代码更新 rango/admin.py。
from django.contrib import admin
from rango.models import Category, Page
...
# 添加这个类,定制管理界面
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug':('name',)}
# 注册定制界面的类
admin.site.register(Category, CategoryAdmin)

在管理界面中添加一个分类试试。
第二个问题也不难解决,只需把 slug 字段设为唯一的。为 slug 字段添加约束:
slug = models.SlugField(unique=True)
添加这个约束之后便可以通过别名唯一标识分类。你可能想在之前就添加唯一性约束,但是这样
一来执行迁移时把别名都设为空字符串就会遇到问题,因为违背了唯一性约束。此外也可以删除
数据库,然后重建,但这并不适合所有情况。

◆ 迁移混乱 ◆

事先最好规划好数据库,尽量不修改。填充脚本的作用是便于删除数据库后重建。
有时,删除数据库后重建比找出问题后再设法解决要方便。你可以练习编写一个脚本,输出
数据库中的数据。这样每次修改数据库都可以把数据输出到一个文件中保存起来,供以后查
看。

创建分类页面的步骤
为了实现可通过 /rango/category/<category-name-slug>/ 访问的分类页面,我们要做几处修改。基
本步骤如下:
➊ 把 Page 模型导入 rango/views.py 模块。
➋ 在 rango/views.py 模块中定义一个新视图,命名为 show_category() 。这个视图有个额外的
参数, category_name_slug ,用于传入编码后的分类名称。为了编码和解码
category_name_slug ,要定义两个辅助函数。
➌ 创建一个模板,templates/rango/category.html。
➍ 更新 rango/urls.py. 中的 urlpatterns ,把这个新视图映射到 URL 模式上。
此外还要更新 index() 视图和 index.html 模板,添加指向分类页面的链接。

分类视图
在 rango/views.py 中,首先导入 Page 模型,即把下述导入语句添加到文件顶部:

分类视图

在 rango/views.py 中,首先导入 Page 模型,即把下述导入语句添加到文件顶部:

def show_category(request, category_name_slug):# 创建上下文字典,稍后传给模板渲染引擎context_dict = {}
try:# 能通过传入的分类别名找到对应的分类吗?# 如果找不到,.get() 方法抛出 DoesNotExist 异常# 因此 .get() 方法返回一个模型实例或抛出异常category = Category.objects.get(slug=category_name_slug)# 检索关联的所有网页# 注意,filter() 返回一个网页对象列表或空列表pages = Page.objects.filter(category=category)# 把得到的列表赋值给模板上下文中名为 pages 的键context_dict['pages'] = pages# 也把从数据库中获取的 category 对象添加到上下文字典中# 我们将在模板中通过这个变量确认分类是否存在context_dict['category'] = category
except Category.DoesNotExist:# 没找到指定的分类时执行这里# 什么也不做# 模板会显示消息,指明分类不存在context_dict['category'] = Nonecontext_dict['pages'] = None
# 渲染响应,返回给客户端
return render(request, 'rango/category.html', context_dict)

这个视图的基本步骤与 index() 视图一样。首先定义上下文字典,然后尝试从模型中提取数据,
并把相关数据添加到上下文字典中。我们通过传给 show_category() 视图函数的
category_name_slug 参数确认要查看的是哪个分类。如果通过别名找到了分类,获取与之关联的
网页,并将其添加到上下文字典 context_dict 中。

分类模板
下面为这个新视图创建模板。在 <workspace>/tango_with_django_project/templates/rango/ 目录中
新建 category.html 文件,写入下述代码。

1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Rango</title>
5 </head>
6 <body>
7 <div>
8 {% if category %}
9 <h1>{{ category.name }}</h1>
10 {% if pages %}
11 <ul>
12 {% for page in pages %}
13 <li><a href="{{ page.url }}">{{ page.title }}</a></li>
14 {% endfor %}
15 </ul>
16 {% else %}
17 <strong>No pages currently in category.</strong>
18 {% endif %}
19 {% else %}
20 The specified category does not exist!
21 {% endif %}
22 </div>
23 </body>
24 </html>

上述 HTML 代码再次展示了如何通过 {{ }} 标签使用模板上下文中的数据。我们访问了 category
和 pages 对象,以及它们的字段,例如 category.name 和 page.url 。
如果 category 存在,再检查分类下有没有网页。如果有,使用模板标签 {% for page in pages %}
迭代网页,显示 pages 列表中各网页的 title 和 url 属性。网页的信息在一个 HTML 无序列表
( <ul> 标签)中显示。如果你不熟悉 HTML,可以查看 W3Schools.com 网站中的 HTML 教程,
学习不同的标签。

◼ 条件判断模板标签 ◼

使用 Django 模板的条件标签 {% if %} 判断上下文中有没有某个对象十分方便。为了避免出
错,应该检查对象是否存在。
在模板中检查条件(例如上例中的 {% if category %} )也更符合语义。条件判断的结果直
接影响呈献给用户的页面。记住,Django 应用表现层的逻辑应该封装在模板中。

带参数的 URL 映射
下面看看 category_name_slug 参数的值是如何传给 show_category() 视图函数的。打开 Rango 应
用的 urls.py 文件,把 urlpatterns 改成下面这样:

urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^about/$', views.about, name='about'),
url(r'^category/(?P<category_name_slug>[\w\-]+)/$',
views.show_category, name='show_category'),
]

我们添加了一个相当复杂的 URL 模式,当 URL 匹配
r'^category/(?P<category_name_slug>[\w\-]+)/$' 时调用 views.show_category() 函数。
这里有两点要注意。首先,URL 模式中有个参数,即 <category_name_slug> ,在视图中可以访
问。声明带参数的 URL 时,要确保对应的视图中有那个参数。其次,正则表达式 [\w\-]+ 匹配连
续的数字字母(即 a-z 、 A-Z 或 0-9 ,正则表达式中的 \w )和连字符(正则表达式中的 \- ),而且
可以匹配任意个(正则表达式中的 [ ]+ )。
新增的 URL 模型匹配 rango/category/ 和末尾的 / 之间的数字字母和连字符序列。匹配的序列存
储在参数 category_name_slug 中,传给 views.show_category() 函数。例如,对 rango/category/
python-books/ 这个 URL 来说, category_name_slug 参数的值是 python-books 。然而,如果 URL
是 rango/category/££££-$/,那么 rango/category/ 和末尾的 / 之间的字符与正则表达式不匹配,此
时将得到“404 not found”错误,因为没有与之匹配的 URL 模式。
Django 应用中的视图函数必须至少有一个参数。这个参数通常命名为 request ,通过它获取与
HTTP 请求有关的信息。如果 URL 中带有参数,必须为对应的视图函数声明额外的具名参数。鉴
于此, show_category() 视图才定义为 def show_category(request, category_name_slug) 。

修改 index 模板
新视图可用了,但是还有一件事要做。我们要修改首页的模板,为列出的分类添加链接,指向分
类页面。更新 index.html 模板,加入指向分类页面的链接。

<!DOCTYPE html>
{% load staticfiles %}
<html>
<head>
<title>Rango</title>
</head>
<body>
<h1>Rango says...</h1>
<div>
hey there partner!
</div>
<div>
{% if categories %}
<ul>
{% for category in categories %}
<!-- 修改下面这一行,添加链接 -->
<li>
<a href="/rango/category/{{ category.slug }}">{{ category.name }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no categories present.</strong>
{% endif %}
</div>
<div>
<a href="/rango/about/">About Rango</a><br />
<img src="{% static "images/rango.jpg" %}" alt="Picture of Rango" />
</div>
</body>
</html>

这里也是使用 HTML <ul> 标签定义一个无序列表,里面有一系列列表项目( <li> ),其中有一个
HTML 超链接( <a> )。超链接有个 href 属性,其值为 /rango/category/{{ category.slug }} 。
例如,“Python Books”分类对应的 URL 是 /rango/category/python-books/ 。

Django模型、模板和视图相关推荐

  1. Django:模板与视图

    一.使用模板传递简单的参数 from django.shortcuts import renderdef myhtml_view(request):username = "admin&quo ...

  2. django模型查询_如何在Django中编写有效的视图,模型和查询

    django模型查询 I like Django. It's a well-considered and intuitive framework with a name I can pronounce ...

  3. Django 使用模板页面,块标签,模型

    1.Django 使用模板页面 Django对于成体系的页面提出了模板继承和模板加载的方式. 1.导入静态页面 2.导入静态文件(css,js,images) 3.修改页面当中的静态地址 1.sett ...

  4. Django模板、配置文件、静态文件及案例实现(创建模板、设置模板查找路径、模板接收视图传入的数据、模板处理数据、BASE_DIR、DEBUG、本地语言与时区、App应用配置)

    1.Django模板 网站如何向客户端返回一个漂亮的页面呢? 漂亮的页面需要html.css.js. 可以把这一堆字段串全都写到视图中, 作为HttpResponse()的参数,响应给客户端. 存在的 ...

  5. 使用Python Django开发web应用5 URL映射、模板和视图

    版本声明:转载请注明出处.未经允许,禁止商业用途. 使用Python Django开发web应用5 URL映射.模板和视图 ----刘一凡 创建模板 在D:\django\web\blog\中创建te ...

  6. 4Python全栈之路系列之Django模型

    Python全栈之路系列之Django模型 MTV开发模式 把数据存取逻辑.业务逻辑和表现逻辑组合在一起的概念有时被称为软件架构的Model-View-Controller(MVC)模式.在这个模式中 ...

  7. 【Django】MTV(Django)模型

    MTV(Django)模型 MVC模型 MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的.松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视 ...

  8. Django模型(一)

    Django模型(一) 文章目录 Django模型(一) 一.配置Django使用mysql数据库 二.案例 1.定义模型类 2.打开booktest/models.py文件 3.迁移 4.测试数据 ...

  9. Django的View(视图)

    Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误, ...

  10. Django 博客开发教程 6 - 真正的 Django 博客首页视图

    在此之前我们已经编写了 Blog 的首页视图,并且配置了 URL 和模板,让 Django 能够正确地处理 HTTP 请求并返回合适的 HTTP 响应.不过我们仅仅在首页返回了一句话:欢迎访问我的博客 ...

最新文章

  1. uva1025城市里的间谍
  2. oracle大于当前月,oracle 现阶段年 当前月 当前周 当前日
  3. python的变量命名及其使用
  4. Android HAL层与Linux Kernel层驱动开发简介
  5. padding卷积的两种方式“SAME”和“VALID”
  6. plsql tables 没有表_技术分享 | 在磁盘上查找 MySQL 表的大小
  7. OpenCV图像直方图案例
  8. ipq8064 openwrt 上KGDB工作不正常
  9. 层叠上下文、层叠层级、层叠顺序
  10. 两个正态总体方差比的置信区间
  11. 持刀男子也地级市小女子背景
  12. 增加PRODUCT_BOOT_JARS及类
  13. Flask框架四:模板继承以及豆瓣案例
  14. 【Lilishop商城】No3-2.模块详细设计,系统设置(系统配置、行政区划、物流公司、滑块验证码图片、敏感词过滤)的详细设计
  15. 【Games101】图形的基础变换 总结
  16. 打开程序,出现最佳分辨率提示窗口,导致程序跳出WIN10
  17. 微信公众平台测试号登录入口地址
  18. ae怎么设置gpu渲染_有玩AE的吗?求教GPU渲染问题!!
  19. SourceInsight4 破解版安装
  20. 4. iconfont 字体图标无法正常渲染显示

热门文章

  1. 网银打印回单显示服务器不能创建对象,打开应用弹出提示“Activex部件不能创建对象”的解决方法...
  2. ubuntu手动下载安装软件包
  3. 百度离线地图开发API
  4. Sql Server2014 安装Northwind数据库
  5. 请熟悉SQL server的高手赐教。
  6. win10任务栏全透明
  7. CMMI2.0和1.3之间的区别有哪些?
  8. 深度学习之美——M-P神经元模型
  9. 服务器上怎么强制删除文件夹,Windows10系统强制删除文件的方法
  10. cruzer php sandisk 闪迪u盘量产工具_SanDisk Cruzer CZ36闪迪U盘 怎么量产