一、模板层简介
-
模板简介
模板是动态生成HTML的便捷方法,包含HTML需输出的静态部分以及动态插入内容的一些特殊语法。
Django后端内置一个自己的模板系统,称为Django template language(DTL)。后端也可以使用第三方提供的模板引擎,最流行的是jinja2引擎。
-
简单用法:
使用
render(request, '模板.html', 字典)
方法来渲染模板,将变量以字典形式传递给模板进行替换。比如,在视图中:
render(request, 'index.html', {'name': 'hugh'})
在变量很多的情况下,可以使用
locals()
方法,将视图中的局部变量全部以字典形式传递给模板,简化步骤。如:render(request, 'index.html',locals())
。然后在模板中:
<h1>My name is {{ name }}!</h1>
这样,就会将“My name is hugh!”以标题样式展现在网页上。
二、变量
当模板引擎遇到一个变量时,它会计算该变量并将其替换为得到的结果。
变量名由字母、数字和下划线的组成,但不能以下划线开头,也不能是数字。
-
基本语法:
将上下文中的变量,输出到html中。
{{ 变量名 }}
-
如果变量传入的是一个函数名,那么会自动调用该函数,并将返回值替换到此。但是如果该函数需要参数,则没有办法通过模板传参,它就不会调用函数,也不会报错,不会显示任何东西。
-
如果传入的是类名,模板也会自动加
()
,进行调用,实例化,输出__str__
方法的返回值。 -
简而言之,对于所有可调用对象,django模板都会试着调用,并将返回值替换到html中。
-
字典、属性和列表等的取值,只能通过点符号
.
实现,点后面跟键、属性名、索引,不能使用[]
或get
等方法。
三、过滤器
过滤器用来修改显示的变量结果。
-
基本语法:
{{ 数据|过滤器:参数}}
过滤器可以是链式的,一个过滤器后面可以跟着一个过滤器。
-
常用过滤器:
统计a的长度:{{ a|length }} 设置a的默认值为“嘤嘤怪”,如果a的值为False,就使用默认值:{{ a|default:'嘤嘤怪' }} 将文件大小file_size,以更加人性化的格式输出:{{ file_size|filesizeformat }} 将时间time格式化后输出: {{ time|date }} 输出:2067年1月23日 {{ time|date:'Y-m-d H:i:s' }} 输出:2067-01-23 10:32:09 对s进行切片,从0到4(不包括4),步长为2:{{ s|slice'0:4:2' }} 按照字符从s中截取10个字符,其中包含最后的三个点:{{ s|truncatechars:10 }} 输出:随便写点什么吧... 按照空格从s中截取5个单词,不包含最后的三个点:{{ s|truncatewords:5 }} 输出:随 便 写 点 什... 移除s中的字符*:{{ s|cut:'*'}} 使用$拼接列表l的元素:{{ l|join:'$' }} python的+运算符:{{ i|add:10 }}或{{ s|add:'abc' }} 将字符串ele='<h1>嘿嘿嘿</h1>'转移,按照html进行渲染,而不是当作普通的字符串:{{ ele|safe }} 取消转义,直接按照字符串输出'<h1>嘿嘿嘿</h1>':{{ ele }}
四、标签
标签(不是指html的标签)在渲染过程中提供任意逻辑。可以是任意内容,也可以是if、for等语句,甚至可以放其他模板语句。
-
基本语法:
{% 标签 参数1 参数2 …… %}
-
for循环:
{% for i in l %} {{ i }} 循环取出的变量 {{ forloop }} {% empty %} …… {% endfor %}
变量
{{ forloop }}
是一个字典,保存着循环计数等信息:变量名 描述 forloop.counter
循环计数器,表示当前循环的索引(从 1
开始)。forloop.counter0
循环计数器,表示当前循环的索引(从 0
开始)。forloop.revcounter
反向循环计数器(以最后一次循环为 1
,反向计数)。forloop.revcounter0
反向循环计数器(以最后一次循环为 0
,反向计数)。forloop.first
当前循环为首个循环时,该变量为 True forloop.last
当前循环为最后一个循环时,该变量为 True forloop.parentloop
在嵌套循环中,指向当前循环的上级循环 当
l
为空或不存在时,才会输出{% empty %}
下面的内容。 -
if判断:
{% if xxx %} …… {% elif yyy %} …… {% else %} …… {% endif %}
-
with起别名:
{% with aba.abb.aab as a %} {{ a }} 在with语句内,可以直接使用a代表那一大串 {% endwith %}
五、自定义过滤器和标签
1. 自定义过滤器
-
第一步:
先在app文件夹中,创建一个
templatetags
子文件夹,名称千万不要写错。 -
第二步:
在
templatetags
文件夹中,创建一个任意名称的.py
文件。 -
第三步:
在
.py
文件中,定义过滤器:@register.filter(name='your_filter') # 过滤器名字随便写,不写默认使用下面的函数名 def my_filter(): # 函数名随便写 pass
注意:过滤器的参数最多有两个。
-
第四步:
在模板文件中,使用自定义过滤器:
{% load 自定义过滤器所在py文件的文件名 %} {{ xxx|过滤器名称:参数 }}
2. 自定义普通标签
-
第一步:
先在app文件夹中,创建一个
templatetags
子文件夹,名称千万不要写错。 -
第二步:
在
templatetags
文件夹中,创建一个任意名称的.py
文件。 -
第三步:
在
.py
文件中,定义标签:@register.simple_tag(name='your_tag') # 标签名字随便写,不写默认使用下面的函数名 def my_tag(): # 函数名随便写 pass
注意:标签的参数没有个数限制。
-
第四步:
在模板文件中,使用自定义过滤器:
{% load 自定义标签所在py文件的文件名 %} {% 标签名称 参数 …… %}
六、模板继承
模板继承可以让我们重用部分页面的html代码,减少代码冗余。
比如说,我们的某个网站的所有页面,都有相同的导航条和底栏。于是,我们就可以将导航条和底栏单独写在一个html文件中,比如叫做base.html
。在其它所有的页面中,使用模板语法,继承这个文件,达到省去重复写这部分代码的目的。
-
在
base.html
中:导航条部分…… {% block content %} {# content是对下面的内容随便起的名字 #} 这一部分内容,被继承之后可以修改 …… {% endblock %} 底栏部分……
-
其他继承
base.html
的文件中:{% extends "base.html" %} {% block content %} 这里进行修改,会完全覆盖掉被继承文件的内容 …… {% endblock %}
-
注意:
{% block xxx %}
可以有多个,但不宜太多。如果不想重写
{% block xxx %}
中的内容,而是想用父模板base.html
的,可以使用{{ block.super }}
变量。{% block xxx %}
不仅可以标记html代码,还可以标记css和js代码。
最后的效果就是,每个页面都有相同的导航条和底栏,但各自都可以有不同的content部分。
七、包含标签
加载一个模板,并在当前上下文中进行渲染。这是一种在模板中 “包含” 其他模板的方式。
包含标签会使用另一个模板渲染数据,然后将结果放到当前模板中。
例如, Django 的后台利用自定义模板标签在表单页的底部展示按钮。这些按钮看起来一样,但是连接目标根据被编辑的对象不同而不同。(在后台例子中,即 submit_row
标签。)
{% include "title.html" %}
这样,title.html
中的内容就会被渲染到{% include "title.html" %}
所在的地方了。
可以使用关键字参数向模板传递额外的上下文:
{% include "name_snippet.html" with 形参1="实参1" 形参2="实参2" %}
自定义包含标签
-
第一步:
先在app文件夹中,创建一个
templatetags
子文件夹,名称千万不要写错。 -
第二步:
在
templatetags
文件夹中,创建一个任意名称的.py
文件。 -
第三步:
在存放模板的
templates
文件夹中,创建自己需要的模板文件。 -
第四步:
在
.py
文件中,定义包含标签:@register.inclusion_tag('menu.html') def my_itag(): # 函数名随便写 …… return xxx # 会将 xxx 传递给 menu.html进行渲染
menu.html
便是需要渲染的模板,它在渲染完成后会放回使用了包含标签的模板中。 -
第五步:
在模板文件中,使用自定义过滤器:
{% load 自定义包含标签所在py文件的文件名 %} {% 函数名称 参数 …… %}
上面自定义标签的写法只适用于简单的逻辑,更加复杂的逻辑需要更加复杂的写法,建议直接看文档:传送门