本文共 6013 字,大约阅读时间需要 20 分钟。
视图函数的作用是生成请求的响应,这种响应通常就是用户所看到的html网页。模板就是带有模板语法({ { }}, {% %}
)的html文件,它能接收视图函数传递的变量,通过模板引擎,模板被渲染成html页面。
在模板中,使用{ { }}
结构表示一个变量,它是一种特殊的占位符,告诉模板引擎,这个位置的值从渲染模板时传入的变量获取;使用{% %}
结构渲染标签(控制结构)。
模板一般放在应用下的templates文件夹,Django的模板渲染引擎会自动查找所有应用下这个文件夹,直到找到指定的模板,因此如果不同应用下有同名的模板,Django很可能找错。因此建议的做法是,在每个应用下的templates文件夹下创建以应用名命名的文件夹,将与该应用相关的模板放在这个文件夹中,就像这样:app/templates/app/XXX.html
。当视图函数返回render响应时,相应地在模板名称前加上app的名字,就像这样:return render('app/XXX.html')
Django的模板引擎能识别python中所有类型的变量,对于列表、字典、和对象这些复杂的变量,我们可以通过万能的句点法(深度查询)来访问集合或对象,比如:
对列表取值:{
{ list.index }}对字典取值: {
{ dict.key }}访问对象的属性: {
{ obj.attr }}
作用:修改变量在模板中的显示
格式:{ { var|filter: arg }}
注意,过滤器函数默认接收变量,除此之外,最多只能接收一个参数 看个栗子:
1.我们在视图函数中定义一些变量,通过locals()
全部传入模板渲染 def index(request): string = 'he l lo' day = datetime.datetime.now() l = [] post = "this is my post, it's very very very long" k = ['cat', 'dog', 'pig'] size = 12345678 return render(request, 'blog/index.html', locals()) # 注意,blog前不要加/ # locals() 将视图中的所有变量对应到模板中的变量
2.在模板中应用过滤器来修改变量
filter过滤器效果!
{ { string }} --> { { string|cut:" " }} 剔除指定字符串
{ { day }} --> { { day|date:"Y-m-d" }} 格式化日期
{ { l }} --> { { l|default:"查询结果为空" }} 当集合为空时,设置默认显示,比如数据库查询结果为空时,我们自定义前端的提示信息
{ { post }} --> { { post|truncatewords:6 }} 截断指定数量的单词,可用于显示文章摘要
{ { k }} --> { { k|join:", " }} 拼接列表
{ { size }} --> { { size|filesizeformat }} 显示友好的文件大小
3.浏览器显示效果:
4.变量过滤器一览
过滤器 | 说明 |
---|---|
add | 给变量加上一个值 |
addslashes | 给变量中的引号前加/斜线 |
capfirst | 首字母大写 |
lower | 转换为小写 |
truncatewords:30 | 截断指定数量的单词,可用于显示文章摘要 |
join | 用指定字符拼接列表 |
default | 如果变量为空或false,使用默认值 |
length | 显示字符串/列表的长度 |
filesizeformat | 显示易读的文件大小 |
date | 格式化日期字符串 |
cut | 从字符串中移除指定的字符 |
safe | 渲染值时不转义。出于安全考虑,模板引擎会转义所有的变量。如果确实需要显示变量中的html代码,就可以使用safe过滤器。不要对不可信的变量使用safe过滤器,比如用户提交的表单中输入的文本,可能包含攻击代码。 |
过滤器也支持链式操作:
{ { var|filter1|filter2 }}
5.更多过滤器的使用,请参考
过滤器本质就是一个函数,只需要如下几步,我们也可以定制自己的过滤器
1. 将当前应用添加到settings.py的INSTALLED_APPS
列表中 2. 在项目的应用文件夹下新建一个包,命名为templatetags
3. 在刚刚新建的包下写一个脚本,比如my_filter.py: ```from django import templateregister = template.Library()# 导入template 并实例化一个对象,命名为 register@register.filter # 装饰自定义函数为过滤器def num_to_char(x): # 自定义函数,将数字转为字符 return chr(x)```
4. 在模板的<head>
标签内中导入自定义的过滤器(使用前导入就行,不一定非要在<head>
内):{% load my_filter %}
。另外,发现一个问题,自定义过滤器导入后,自带的过滤器可能工作不正常,具体原因不明,有知道的伙伴可以分享下。
自定义标签的流程和自定义过滤器是相同的,只是装饰器修改为@register.simple_tag
{% func var [arg1] [arg2] ... [argn] %}
二者的其他差异: 1. 过滤器除了接收变量本身,最多可以额外接收一个参数,而自定义标签无限制 2. 过滤器可以配合其它标签使用,比如if控制语句: ```{% if var|filter %} do something```但是自定义标签不能这样使用。补充:自定义标签的另一种形式 inclusion_tag:
应用下新建templatetags
目录,新建脚本custom_tag.py
,通过inclusion_tag
自定义标签
from django.template.library import Libraryregister = Library()@register.inclusion_tag('sample.html')def get_result(x): print('do something') return { 'content': 'XXX', 'comments': ['aa', 'bb', 'cc']}
说明:
inclusion_tag
接收一个模板路径,这里是”sample.html”,并将函数的返回值拿到模板中渲染定义”sample.html”模板:
{ { content }}
调用自定义标签:
{% load custom_tag %}{% get_result x %}
Django的模板引擎提供了多种控制结构,用来改变模板的渲染流程。
{% if user %} Hello, { { user }}!{% else %} Hello, { { Stranger }}!{% endif %}
渲染从数据库取出的一组评论,使用for循环可以实现这一需求
forloop用在for循环内,配合if语句,可以用来控制循环:
1. forloop.counter 索引,从1开始,可用于显示清单中条目的序号 2. forloop.counter0 索引,从0开始 3. forloop.revcounter 索引,倒序到1 4. forloop.revcounter0 索引,倒序到0 5. forloop.first 当第一次循环时,值为True 6. forloop.last 当第一次循环时,值为False看个栗子:
for循环可以可以接受一个{% empty %}
从句,如果循环的对象为空,将显示{% empty %}
从句下的内容:
模板继承(extends)类似Python中的类继承。它允许我们重用模板中相同的部分,定制不同的部分。首先,创建一个名为base.html的基模板:
{% block head %}{% block title %}Title{% endblock %} {% endblock %}{% block body %}{% endblock %}
block标签定义的块可以在衍生模板中修改,并且每个block标签都有名字。这里,我们只是简单定义了head, title(因为每个页面都应该显示一个不同title), body的块。注意,title包含中head中。下面我们来写一个基模板的衍生模板:
{% extends 'base.html' %}{% block title %}Home{% endblock %}{% block head %} { { block.super }} {% endblock %}{% block body %}Hello, World!
{% endblock %}}
{% extends 'base.html' %}
继承指令放在首行,声明该模板衍生自base.html。我们在衍生模板中重定义了三个block的内容,模板引擎会根据block名字,将其插入适当的位置。另外,通过{% block.super %}
,可以重用原来block中的内容,以便在其基础上添加内容。
需要在多处重复使用的模板代码片段可以写在单独的文件,再包含(include)在要用的模板中,以避免重复:
{% include 'common.html' %}
{% url %}
通过视图函数别名,生成url绝对路径,它还可以接收路由分组的参数: {% url 'name' v1 v2 %}
{% with %}
用更简单的变量名替代复杂的变量名{% with total=business.employees.count %} { { total }} employee{ { total|pluralize }}{% endwith %} {% with business.employees.count as total %}...{% endwith %}
{% verbatim %}
告诉模板引擎,不要渲染这个标签内的内容{% verbatim %} { { 我就是要显示两个花括号! }}{% endverbatim %}
{% load %}
载入自定义的模板标签,记住,目标不加引号更多标签,请参考
令某些变量在所有模板中可用,比如,网站的顶部分类菜单,在很多页面中都是相同的。
settings.py:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', # ... 'app.views.get_funcs', # 视图加入上下文处理器列表 ], }, },]
FUNCTIONS = [ (1,"园子"), (2,"随笔"), (3,"新闻"), (4,"博文"),]
views.py
def get_funcs(request): return ({ "funcs": settings.FUNCTIONS})
template: funcs变量在所有模板中可用
{% for func in funcs %}