Django之模板层
作为一个Web框架,Django
需要一种动态生成HTML的便捷方法。最常用的方法依赖于模板。模板包含所需HTML输出的静态部分以及描述动态内容将被插入的一些特殊语法。
Django之视图层中我们可以通过render
方法,将数据渲染到指定的html
模板中,本文介绍如何在模板中处理数据。
模板变量
在模板中输出变量的语法与vue
一样使用双大括号:
{{var_name}}
1 | # views.py |
结果:
注意:句点符也可以用来引用对象的方法(无参数方法):
1 | {% raw %}{{dic.name.upper}}{% endraw %} |
模板过滤器
即在模板中使用函数,语法为:{{obj|filter__name:param}}
过滤器可以用来修改变量的显示样式。
过滤器的使用方式:{{变量|过滤器方法}}
。过滤器可以连续使用,形式如:{{变量|过滤器方法1|过滤器方法2}}
。
注意变量、管道符:(|)和过滤器方法之间不能有空格。
某些过滤器还可以接收参数,例如:{{titleltruncatewords:30}}
,这句代码的意思是显示title
的前30 个单词。
如果过滤器参数包含空格的话,参数就要用引号包括,例如:{{list|join:","}}
。
下面介绍几个常用的过滤器:
default
如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
1 | {% raw %}{{ value|default:"nothing"}}{% endraw %} |
capfirst
首字母大写:{{valuelcapfirst}}
。
length
返回值的长度。它对字符串和列表都起作用。例如:
1 | {% raw %}{{ value|length }}{% endraw %} |
如果 value
是 ['a', 'b', 'c', 'd']
,那么输出是 4。
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 13 KB
, 4.1 MB
, 102 bytes
, 等等)。例如:
1 | {% raw %}{{ value|filesizeformat }}{% endraw %} |
如果 value
是 123456789,输出将会是 117.7 MB
。
cut
删除指定值,例如去掉字符串中的空格:{{value|cut:""}}
。
如果value 是“ String with spaces ”,那么输出Stringwithspaces
。
date
如果 value=datetime.datetime.now()
1 | {% raw %}{{ value|date:"Y-m-d"}}{% endraw %} |
escape
将字符串进行HTML 转意,例如:
1 | {% raw %} |
如果value
是“<Django>
”,则输出<Django>
。
slice
如果 value="hello world"
1 | {% raw %}{{ value|slice:"2:-1" }}{% endraw %} |
filesizeformat
将文件大小按照人类可读的形式显示,例如一个文件有123456789
个字节,那么使用filesizeformat
将会显示成117 .7 MB
,语法形式:{{valuejfilesizeformat}}
。
truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“…”)结尾。
参数:要截断的字符数
例如:
1 | {% raw %}{{ value|truncatechars:9 }}{% endraw %} |
safe
Django
的模板中会对HTML
标签和JS
等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML
元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor
编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django
中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe
”的方式告诉Django
这段代码是安全的不必转义。比如:
1 | value="<a href=''>点击</a>" |
更多内置过滤器可参考官方文档:https://docs.djangoproject.com/zh-hans/2.0/ref/templates/builtins/#built-in-filter-reference
模板标签
标签看起来像是这样的: {% tag %}
。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} ...
标签 内容 … {% endtag %}
)。
for
标签
遍历每一个元素:
1 | {% raw %} |
可以利用{% for obj in list reversed %}
反向完成循环。
遍历一个字典:
1 | {% raw %} |
注:循环序号可以通过{{forloop}}{% endaw %}`显示
从句,以便在给出的组是空的或者没有被找到时,可以有所操作。1
2
3
4
5
6forloop.counter 当前循环位置(以数字1位起始)
forloop.counter0 当前循环位置(以数字0位起始)
forloop.revcounter 反向循环位置(列表的最后一位是l ,列表第一位是n )
forloop.revcounter0 反向循环位置(列表的最后一位是0 , 列表第一位是n- 1 )
forloop.first 如果是当前循环的第一位,返回True
forloop.last 如果是当前循环的最后一位,返回True
1 | {% raw %} |
if
标签
{% raw %}{% if %}{% endraw %}
会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
1 | {% raw %} |
with
使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
例如:
1 | {% raw %} |
csrf_token
这个标签用于跨站请求伪造保护
更多内置标签参见官方文档:https://docs.djangoproject.com/zh-hans/2.0/ref/templates/builtins/#built-in-tag-reference
人性化语义标签
除了上述功能性标签外, Django
还提供了很多辅助性标签,这些标签只是为了使变量输
出变得更加可读,下面对这些标签进行简单介绍。
首先为了使用这些标签,需要在INSTALLED_APPS
中注册django .contrib.humanize
,
然后在模板中引用humanize
:{% raw %}{% load humanize % }{% endraw %}
apnumber
将数字1 ~ 9 转换为英文单词,但是其他数字不转换,如数字10 将被原样输出。
示例:
1 | 数字1 被转换为one ; |
如果当前工程语言是中文的话,数字将会被转换为对应的汉字,例如:
1 | {% raw %} |
如果当前工程语言是中文的话,数字将会被转换为对应的汉字,例如:
输出:
1 | 一 |
intcomma
输出以逗号分隔的数字,如4500 输出4,500, 4500.2 输出4,500.2 。
intword
以文字形式输出数字,如1000000 输出“ 1.0 million ”, 1200000 输出“ 1,2 Million ” 。
对于中文系统,将会输出对应的中文,如1200000 输出" 1.2 百万” 。
naturalday
将当前日期以及前后一天输出为today 、yesterday 和tomorrow ,而中文系统分别输出
“今天”“昨天”和“明天” 。
naturaltime
对于日期时间格式,时间值与系统当前时间比较,然后输出结果。如当前时间输出
“ now ”, 29 秒前输出“ 29 sec onds ago ” 。如果使用naturaltime 输出今天、昨天、明天的话,
就会变成“现在”“ 23 小时·以后”“ 1 日之前” 。
ordinal
将数字转换为序数,如l 输出“ 1 st ”; 2 输出“ 2nd ”; 3 输出“ 3rd ” 。注意此时中文与
英文的输出一样。
自定义标签或过滤器
- 确认settings已配置当前应用(命令行创建应用时系统默认会将该应用添加至
settings
之INSTALLED_APPS
中) - 当前应用中创建
templatetags
目录
1 | myproject |
- 创建自己过滤器和标签文件,如
myapp/templatetags/diy_tags.py
1 | from django import template |
- 在要使用自定义标签和过滤器的
html
模板中导入自定义标签文件
1 | {% raw %} |
- 在模板中使用自定义标签和过滤器
1 | {% raw %} |
num
为22的情况下渲染出的效果如下:
模板继承
Django
模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。
通过从下面这个例子开始,可以容易的理解模版继承:
我们创建一个基模板layout.html
:
1 | {% raw %} |
当我们整体需要这样,只要改变某一块内容的时候,就可以继承它,我们假设为index.html
1 | {% raw %} |
就这么简单,我们看下渲染后页面内容
1 | <html lang="en"> |
使用继承的一些提示:
如果你在模版中使用
{% raw %}{% extends %}{% endraw %}
标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。在base模版中设置越多的
{% raw %}{% block %}{% endraw %}
标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个
{% raw %}{% block %}{% endraw %}
中。如果需要从父模板获取块的内容,则
{{block.super}}
变量将起作用。如果要添加到父块的内容,而不是完全重写父块,则这非常有用,应用场景如:基模板包含基本的css或者js静态资源,其他页面除了要使用这些基础的静态资源以外还要使用自己页面固定的静态资源,这个时候使用该变量可以很好地解决为了更好的可读性,你也可以给你的
{% raw %}{% endblock %}{% endraw %}
标签一个 名字 。例如:
1 | {% raw %} |
在大型模版中,这个方法帮你清楚的看到哪一个 {% raw %}{% block %}{% endraw %}
标签被关闭了。
不能在一个模版中定义多个相同名字的 block
标签。