了解前提:Django请求和响应设置
参考
在前提的演示中, HTML被直接硬编码在 Python 代码之中的用法只是为了方便演示。
但是实际生产中, 将页面的设计和Python的代码分离开会更干净简洁更容易维护。 我们可以使用 Django的 模板系统 (Template System)来实现这种模式
—————————————————————————————————————
视图
每个视图必须要做的只有两件事:返回一个包含被请求页面内容的 HttpResponse
对象,或者抛出一个异常,比如 Http404
。
视图可以从数据库里读取记录,可以使用一个模板引擎(比如 Django 自带的,或者其他第三方的),可以生成一个 PDF 文件,可以输出一个 XML,创建一个 ZIP 文件,你可以做任何你想做的事,使用任何你想用的 Python 库。
—————————————————————————————————————
模板系统基本知识
项目的 TEMPLATES
配置项描述了 Django 如何载入和渲染模板。默认的设置文件设置了 DjangoTemplates
后端,并将 APP_DIRS
设置成了 True。这一选项将会让 DjangoTemplates
在每个 INSTALLED_APPS
文件夹中寻找 "templates" 子目录。
模板文件的路径应该是 : [应用根目录]/templates/[应用名]/[模板名].html
因为 Django 会寻找到对应的 app_directories ,所以你只需要使用 [应用名]/[模板名].html 就可以引用到这一模板了
一、模本概念和组成
模板是一个文本,用于分离文档的表现形式和内容。 模板定义了占位符以及各种用于规范文档该如何显示的各部分基本逻辑(模板标签)。 模板通常用于产生HTML,但是Django的模板也能产生任何基于文本格式的文档。
示例:
<html>
<head><title>Ordering notice</title></head>
<body>
<h1>Ordering notice</h1>
<p>Dear {{ person_name }},</p>
<p>Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:"F j, Y" }}.</p>
<p>Here are the items you've ordered:</p>
<ul>
{% for item in item_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% if ordered_warranty %}
<p>Your warranty information will be included in the packaging.</p>
{% else %}
<p>You didn't order a warranty, so you're on your own when
the products inevitably stop working.</p>
{% endif %}
<p>Sincerely,<br />{{ company }}</p>
</body>
</html>
其中的格式含义
模板变量
:
用两个大括号括起来的文字, 意味着在此处插入指定变量的值。
附:模板变量的解析顺序
模板标签
:
被大括号和百分号包围的文本(例如 {% if ordered_warranty %} )是 模板标签(template tag) 。标签(tag)定义比较明确,即: 仅通知模板系统完成某些工作的标签。
过滤器
:
形如例子中: {{ship_date|date:”F j, Y” }}
格式作为过滤器(filter), 我们将变量ship_date传递给date过滤器,同时指定参数”F j,Y”。date过滤器根据参数进行格式输出。 过滤器是用管道符(|)来调用的。
二、模板结合视图的使用
如果要额外了解模板作为python库的独立运行机制, 还有其中内置标签和模板的特殊行为,
参考: 模板系统独立工作原理总结
由于目前普遍都是模本结合视图一起呈现, 以下主要总结结合使用的方法。
1、首先创建模板结构 [应用根目录]/templates/[应用名]/[模板名].html
2、完善模板内容, 设计模板交互规则
3、创建模板对应视图, 将视图的请求访问注册到urls.py文件
4、在视图中使用template 库的get_template获取模板对象, 使用shortcuts 或template 库的render渲染模板(基础用法), 将复杂的数据或数据对象以字典的形式传递给模本系统, 由后者进行深度变量的查找。
三、在模板中使用Http404方法抛出404, 以便django处理并显示404页面
使用情景, 当数据库根据页面交互数据查不到数据, 需要手动扔出404, 但路由配置失败或者访问到错误路由是, django自动报404,
from django.shortcuts import render
from .models import Question
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
上面这个流程主要是当数据库根据页面交互数据查不到数据, 需要手动扔出404, 其实有一个快捷函数可以直接两步操作一起进行get_object_or_404。
4、去除模板访问的硬编码
由于在模板中定义到api的访问路由由urls.py文件定义, 而后者随时可能会改变一节路由, 故路由在模板中不能进行硬编码。
形如:
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
// polls是路由匹配字符
需要改成:
<li><a href="{% url 'GDweb:detail' question.id %}">{{ question.question_text }}</a></li>
其中GDweb:detail
为命名空间为GDweb的urls.py文件中的参数name为detail的指定路由, 指定之后, 不管路由匹配规则怎么变, 路由名字不变就可精准匹配。
GDweb:detail
代表命名空间为GDweb(对应应用)下的路由, 为了让多应用下Django 知道{% url %}
标签到底对应哪一个应用的 URL,在urls.py文件中, 可以定义app_name
变量指定命名空间。
—————————————————————————————————————
shortcuts 库的一个快捷函数: render()
¶
「载入模板,填充上下文,再返回由它生成的 HttpResponse
对象」是一个非常常用的操作流程。于是 Django 提供了一个快捷函数,我们用它来重写 index()
视图:
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
基于数据库查询为空404抛出的快捷函数: get_object_or_404()
¶
尝试用 模型的get()
函数获取一个对象,如果不存在就抛出 Http404
错误也是一个普遍的流程。Django 也提供了一个快捷函数,下面是修改后的详情 detail()
视图代码:
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
—————————————————————————————————————