Django 作为 Web 框架,需要一种很便利的方法去动态地生成 HTML 网页,因此有了模板这个概念。模板包含所需 HTML 的部分代码以及一些特殊的语法,特殊的语法用于描述如何将数据动态插入 HTML 网页中。
Django 可以配置一个或多个模板引擎(也可以不配置,如果不需要使用模板),模板系统有 Django 模板语言(Django Template Language,DTL)和 Jinja2。Django 模板
语言是 Django 内置的模板语言,Jinja2 是当前 Python 最流行的模板语言。下面以 Django 内置的模板语言为讲述内容,模板配置同第二节。
变量标签
变量是模板中最基本的组成单位,模板变量是由视图函数生成的。如果变量没有被视图函数生成,那么模板引擎解析 HTML 时,模板变量不会显示在网页上。变量以 {{ variable }}
表示,variable
是变量名,变量的类型可以是 Python 支持的数据类型,使用方法如下:
# variable 为字符串类型或整型,如 variable='Python'
{{ variable }}
# 输出 Python
# variable 为字典或数据对象,通过点号 . 来访问其属性值
# 如 variable = { "name" : "Lily", "info": { "home": "BeiJing", "homeplace" : "shangHai"}}
{{ variable.name }}
# 输出Lily
{{ variable.info.home }}
# 输出 BeiJing
模板的变量需要和标签相互结合使用。模板的标签就如 Python 里面的函数和方法,Django 常用的内置标签说明如下表所示:
标签 | 描述 |
---|---|
{% for %} | 遍历输出变量的内容,变量类型应为列表或数据对象 |
{% if %} | 对变量进行条件判断 |
{% csrf_token %} | 生成 csrf_token 的标签,用于防护跨站请求伪造攻击 |
{% url %} | 引用路由配置的地址,生成相应的 URL 地址 |
{% with %} | 将变量名重新命名 |
{% load %} | 加载导入 Django 的标签库 |
{% static %} | 读取静态资源的文件内容 |
{% extends xxx %} | 模板继承,xxx 为模板文件名,使当前模板继承 xxx 模板 |
{% block xxx%} | 重写父类模板的代码 |
在上述常用标签中,每个标签的使用方法都是各不相同的。我们通过简单的例子来进一步了解标签的使用方法,代码如下:
{# for 标签,支持嵌套,myList 可以是列表或某个对象 #}
{# item 可自定义命名,{% endfor %} 代表循环区域终止符,代表这个区域的代码由标签 for 循环输出 #}
{%for item in myList%}
{{ item }}
{% endfor %}
{# if 标签,支持嵌套,判断条件符必须与变量之间使用空格隔开,否则程序会抛出异常 #}
{# { % endif %} 与 {% endfor %} 的作用是相同的 #}
{% if name == "Lily" %}
{{ name }}
{% elif name == "Lucy"%}
{{ name }}
{% else %}
{{ name }}
{% endif %}
{# url 标签,生成不带变量的 URL 地址 #}
{# 相关的路由地址:path('', views.index, name='index') #}
{#字符串 index 是 URL 的参数 name 的值#}
<a href="{% url 'index'%}" target="_blank">首页</a>
{# 生成带变量的 URL 地址 #}
{# 相关的路由地址:path('search/<int:page>.html', views.search, name='search') #}
{# 字符串 search 是 URL 的参数 name 的值,1 是 URL 的变量 page 的值 #}
<a href="{% url 'search' 1 %}" target="_blank">第 1 页</a>
{# total 标签 #}
{% with total = products_total %}
{{ total }}
{% endwith %}
{# load 标签,导入静态文件标签库 staticfiles,staticfiles 来自 settings.py 的 INSTALLED_APPS #}
{% load staticfiles %}
{# static 标签,来自静态文件标签库 staticfiles #}
{% static "css/hw_index.css" %}
在 for
标签中,模板还提供一些特殊的变量来获取 for
标签的循环信息,变量说明如下:
forloop.counter
:获取当前循环的索引,从 1 开始计算。forloop.counter()
:获取当前循环的索引,从 0 开始计算。forloop.revcounter
:索引从最大数开始递减,直到索引到 1 位置。forloop.revcounter()
:索引从最大数开始递减,直到索引到 0 位置。forloop.first
:当遍历的元素为第一项时为真。forloop.last
:当遍历的元素为最后一项时为真。forloop.parentloop
:在嵌套的for
循环中,获取上层for
循环的forloop
。
上述变量来自于 forloop
对象,该对象是模板引擎解析 for
标签时所生成的。下面通过简单的例子来进一步了解 forloop
的使用,例子如下:
{% for name in name_list %}
{% if forloop.counter == 1 %}
<span>这是第一次循环</span>
{% elif forloop.last %}
<span>这是最后一次循环</span>
{% else %}
<span>本次循环次数为:{{ forloop.counter }}</span>
{% endif %}
{% endfor %}
模板继承
模板继承是通过模板标签来实现的,其作用是将多个 HTML 模板的共同代码集中在一个新的 HTML 模板中,然后各个模板可以直接调用新的 HTML 模板,从而生成 HTML 网页,这样可以减少模板之间重复的代码。其代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<a href="{% url 'index' %}" target="_blank">首页</a>
<h1>Hello Django</h1>
</body>
</html>
上述代码是一个完整的 HTML 模板,一个完整的模板有 <head>
和 <body>
两大部分,其中 <head>
部分在大多数情况下都是相同的,因此可以将 <head>
部分写到共用模板中,将共用模板命名为 base.html
,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
在 base.html
的代码中可以看到,<body>
里的内容变为 {% block body %}{% endblock %}
,block
标签相当于一个函数,body
是对该函数的命名,开发者可自行命名。在一个模板中可以添加多个 block
标签,只要每个 block
标签的命名不相同即可。
接着在模板 index.html
中调用共用模板 base.html
,代码如下:
{% extends "base.html" %}
{% block body %}
<a href="{% url 'index' %}" target="_blank">首页</a>
<h1>Hello Django</h1>
{% endblock %}
自定义过滤器
过滤器主要是对变量的内容进行处理,如替换、反序和转义等。通过过滤器处理变量可以将变量的数据格式和内容转化为我们想要的效果,而且相应减少视图函数的代码量。过滤器的使用方法如下:
{{ variable | filter }}
模板引擎解析带过滤器的变量时,首先过滤器 filter
处理变量 variable
,然后将处理后的变量显示在网页上。其中,variable
代表模板变量,管道符号 |
代表变量使用过滤器,filter
代表某个过滤器。变量可以支持多个过滤器同时使用,例如下:
{{ variable | filter | lower }}
在使用的过程中,有些过滤器还可以传入参数,但仅支持一个参数的传入。带参过滤器的使用方法如下:
{{ variable | date: "D d M Y" }}
Django 默认提供的内置过滤器如下所示:
内置过滤器 | 使用形式 | 说明 |
---|---|---|
add | {{ value | add "2" }} | 将 value 的值增加 2 |
addslashes | {{ value | addslashes }} | 在 value 中的引号前增加反斜线 |
capfirst | {{ value | capfirst }} | value 的第一个字符转大写 |
cut | {{ value | cut:arg }} | 从 value 中删除所有 arg 的值。如果 value 是 "String with spaces" ,arg 是 " " ,那么输出的是 ""Stringwithspaces |
date | {{ value | date "D d M Y" }} | 将日期格式数据按照给定的格式输出 |
default | {{ value | default: "nothing" }} | 如果 value 的意义为 False ,那么输出值为过滤器设定的默认值 |
default_if_none | {{ value | default_if_none:"nothing" }} | 如果 value 的意义是 None ,那么输出值为过滤器设定的默认值 |
dictsort | {{ value | dictsort:"name" }} | 如果 value 的值是一个列表,里面的元素是字典,那么返回值按照每个字典的关键字排序 |
dictsortreversed | {{ value | dictsortreversed:"name" }} | 如果 value 的值是一个列表,里面的元素是字典,那么返回值按照每个字典的关键字反序排序 |
divisibleby | {{value | divisibleby:arg }} | 如果 value 能够被 arg 整除,那么返回值将是 True |
escape | {{ value | escape }} | 控制 HTML 转义,替换 value 中的某 HTML 特殊字符 |
escapejs | {{ value | escapejs }} | 替换 value 中的某些字符,以适应 JavaScript 和 JSON 格式 |
filesizeformat | {{ value | filesizeformat }} | 格式化 value ,使其成为易读的文件大小,例如 13KB 、4.1MB 等 |
first | {{ value | first }} | 返回列表中的第一个 Item,例如,如果 value 是列表 ['a', 'b', 'c'] ,那么输出将是 'a' |
floatformat | {{ value | floatformat }} 或 {{ valuel | floatformat:arg }} | 对数据进行四舍五入处理,参数 arg 是保留小数位,可以是正数或负数,如 {{ value | floatformat:"2" }} 是保留两位小数。若无参数 arg ,默认保留 1 位小数,如 {{ value | floatformat }} |
get_digit | {{ value | get_digit:"arg" }} | 如果 value 是 123456789 ,arg 是 2 ,那么输出的是 8 |
iriencode | {{ value | iriencode }} | 如果 value 中有非 ASCII 字符,那么将其转化成 URL 中适合的编码 |
join | {{ value | join:"arg" }} | 使用指定的字符串连接一个 list,作用如同 Python 的 str.join(list) |
last | {{ value | last }} | 返回列表中的最后一个 Item |
length | {{ value | length }} | 返回 value 的长度 |
length_is | {{ value | length_is:"arg" }} | 如果 value 的长度等于 arg ,例如:value 是 ['a','b','c'] ,arg 是 3 ,那么返回 True |
linebreaks | {{ value | linebreaks }} | value 中的 \n 将被 <br/> 替代,并且将整个 value 使用 <p> 包围起来,从而适应 HTML 的格式 |
linebreaksbr | {{value | linebreaksbr }} | value 中的 \n 将被 <br/> 替代 |
linenumbers | {{ value | linenumbers }} | 为显示的文本添加行数 |
ljust | {{ value | ljust }} | 以左对齐方式显示 value |
center | {{ value | center }} | 以居中对齐方式显示 value |
rjust | {{ value | rjust }} | 以右对齐方式显示 value |
lower | {{ value | lower }} | 将一个字符串转换成小写形式 |
make_list | {{ value | make_list }} | 将 value 转换成 list 。例如 value 是 Joel ,输出 [u'J',u'o',u'e',u'l'] ;如果 value 是 123 ,那么输出是 [1,2,3] |
pluralize | {{ value | pluralize }} 或 {{ value | pluralize:"es" }} 或 {{ value | pluralize:"y,ies"}} | 将 value 返回英文复数形式 |
random | {{value | random}} | 从给定的 list 中返回一个任意的 Item |
removetags | {{ value | removetags:"tag1 tag2 tag3..." }} | 删除 value 中 tag1,tag2… 的标签 |
safe | {{ value | safe }} | 关闭 HTML 转义,告诉 Django 这段代码是安全的,不必转义 |
safeseq | {{ value | safeseq }} | 与上述 safe 基本相同,但有一点不同,safe 针对字符串,而 safeseq 针对多个字符串组成的 sequence |
slice | {{ some_list | slice:":2"}} | 与 Python 语法中的 slice 相同,":2” 表示截取前两个字符,此过滤器可用于中文或英文 |
slugify | {{ value | slugify }} | 将 value 转换成小写形式,同时删除所有分单词字符,并将空格变成横线。例如:value 是 Joel is a slug ,那么输出的将是 joel-is-a-slug |
striptags | {{ value | striptags }} | 删除 value 中的所有 HTML 标签 |
time | {{value | time:"H:i"}} 或 {{ value | time }} | 格式化时间输出,如果 time 后面没有格式化参数,那么输出按照默认设置的进行 |
truncatewords | {{ value | truncatewords:2 }} | 将 value 进行单词截取处理,参数 2 代表截取前两个单词,此过滤器只可用于英文截取。如 value 是 Joel is a slug 那么输出将是:Joel is |
upper | {{ value | upper }} | 转换一个字符串为大写形式 |
urlencode | {{ value | urlencode }} | 将字符串进行 URLEncode 处理 |
urlize | {{ value | urlize }} | 将一个字符串中的URL转化成可点击的形式。如果 value 是 Check out www.baidu.com ,那么输出的将是:Check out <a href="http://www.baidu.com">www.baidu.com</a> |
wordcount | {{ value | wordcount }} | 返回字符串中单词的数目 |
wordwrap | {{ value | wordwrap:5 }} | 按照指定长度的分割字符串 |
timesince | {{ value | timesince:arg }} | 返回参数 arg 到 value 的天数和小时数。如果 arg 是一个日期实例,表示 2006-06-01 午夜,而 value 表示 2006-06-01 早上 8 点,那么输出结果返回 8 hours |
timeuntil | {{ value | timeuntil }} | 返回 value 距离当前日期的天数和小时数 |
在实际开发中,如果内置过滤器的功能不太适合实际开发需求,我们可以通过自定义过滤器来解决问题。
首先在 test01
中添加文件和文件夹,如下图所示:
完成上述两个环境配置后,下一步是编写自定义过滤器的实现代码,在 myfilter.py
中添加以下代码:
from django import template
# 声明一个模板对象,也称为注册过滤器
register = template.Library()
# 声明并定义过滤器
@register.filter
def myreplace(value, args):
old_value = args.split(':')[0]
new_value = args.split(':')[1]
return value.replace(old_value, new_value)
上述代码用于实现 HTML 模板的字符串替换功能,与 Python 的 replace
函数相同,过滤器说明如下:
- 首先导入模板功能
template
,通过template
声明Library
对象,将对象赋值给变量register
,这一过程称为注册过滤器。 - 过滤器以函数的形式实现,在函数前使用
register.filter
装饰器来表示该函数是一个过滤器,函数名可自行命名。 - 函数参数可设置一个或两个,如上述的参数分别是
value
和args
,参数value
是 HTML 模板的变量,参数args
是过滤器函数定义的函数参数。 - 过滤器函数最后必须将处理结果返回,否则在使用过程中会出现异常信息。
最后在 HTML 模板中使用我们自定义的过滤器,以 index.html
模板中的 host
变量为例,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
{# 加载自定义的 myfilter 过滤器 #}
{% load myfilter %}
{# 视图函数中定义了 host 变量的值为 "www.zze.xyz" #}
{{ host | myreplace:'zze.xyz:ZZE.XYZ' }}
</body>
</html>
访问效果如下:
评论区