系列文章目录
第一章 Django使用的基础知识
第二章 setting.py文件的配置
第三章 路由的定义与使用
第四章 视图的定义与使用
第五章 二进制文件下载响应
第六章 Http请求&HttpRequest请求类
第七章 会话管理(Cookies&Session)
第八章 文件上传实现
第九章 多种视图view
第十章 Django5模板引擎
文章目录
前言
Django作为Web框架,需要一种很便利的方法动态的生成HTML网页,因此有了模板这个概念。模板包含所需HTML的部分代码以及一些特殊语法,特殊语法用于描述如何将视图传递的数据插入HTML网页中。
Django可以配置一个或多个模板引擎(甚至是0个,如前后端分离,Django只提供API接口,无须使用模板引擎),模板引擎有Django模板语言(Django Template Language,DTL)和jinja3.Django模板语言是Django内置的功能之一,jinja3是当前Python流行的模板语言。本章分别讲述Django模板语言和jinja3的使用方法。
Django5内置模板引擎
Django 内置的模板引擎包含模板上下文(亦可称为模板变量)、标签和过滤器,各个功能说明如下:
-
模板上下文是以变量的形式写入模板文件里面,变量值由视图函数或视图类传递所得。
-
标签是对模板上下文进行控制输出,比如模板上下文的判断和循环控制等。
-
模板继承隶属于标签,它是将每个模板文件重复的代码抽取出来并写在一个共用的模板文件中,其他模板文件通过继承共用模板文件来实现完整的网页输出。
-
过滤器是对模板上下文进行操作处理,比如模板上下文的内容截取、替换或格式转换等。
1.模板上下文
模板上下文是模板中基本的组成单位,上下文的数据由视图函数或视图类传递。它以{{ variable }}表示,variable是上下文的名称,它支持 Python 所有的数据类型,如字典、列表、元组、字符串、整型或实例化对象等。上下文的数据格式不同,在模板里的使用方式也有所差异。
使用变量的一些注意点如下:
- 当模板引擎遇到一个变量,将计算这个变量,然后输出结果
- 变量名必须由字母、数字、下划线、点组成,不能由数字和下划线开头
- 当模板引擎遇到 " . " 的时候,按以下顺序进行解析
- 按照 dict 解析 var[key]
- 按照对象的属性或方法解析 var.var/func
- 按照索引解析 var[index]
- 如果变量不存在,不会引发异常,模板会插入空字符串 ''
- 在模板中使用变量或方法时,不能出现 ()、[]、{}
- 调用方法时,不能传递参数
实例:
在view中添加函数:
py
def modelEngine(request):
myStr = "我是字符串"
class student:
name = '张三'
age = 18
sex = '男'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
lisi = student('李四', 19, '女')
myTuple = ('元组1',443,'元组2',111.1)
myList = [1,2,'ggbond',4,'列表5']
myDict = {'name':'小弟','age':18,'sex':'中性人'}
contentValues = {'msg1': myStr, 'msg2': lisi, 'msg3': myTuple, 'msg4': myList, 'msg5': myDict}
return render(request, 'modelEngine.html',context=contentValues)
urls里加路径:
py
path('modelengine/',helloWorld.views.modelEngine)
添加个模板modelEngine.html:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板引擎测试</title>
</head>
<body>
<p>字符串测试:{{ msg1 }}</p>
<p>对象测试:对象姓名:{{ msg2.name }}、对象年龄:{{ msg2.age }}、对象性别:{{ msg2.sex }}、对象爱好:{{ msg2.hobby }}、对象:{{ msg2}}</p>
<p>元组测试:元组第一个{{ msg3.0 }}、元组第三个"{{ msg3.2 }}"、元组第四个{{ msg3.3 }}、元组:{{ msg3 }}</p>
<p>列表测试:列表第一个:{{ msg4.0 }}、列表第二个:{{ msg4.1 }}、列表第三个:{{ msg4.2 }}、列表第四个:{{ msg4.3 }}、列表:{{ msg4 }}</p>
<p>字典测试:字典键name值:{{ msg5.name }}、字典全部:{{ msg5 }}</p>
</body>
</html>
运行测试127.0.0.1/modelengine/
:
综上,能发现在模板上下文(模板变量)中元组、列表、字典、对象都是用"."来定位索引或键值。实例中没写遇到不存在的索引或键会怎么样,在这里补充一下。遇到这种情况,不会报错,会返回一个空的值。
2.模板标签
标签是对模板上下文进行控制输出,它是以{% tag %}表示的,其中 tag是标签的名称,Django内置了许多模板标签,比如{% if %}(判断标签)、{% for %}(循环标签)或{% url %}(路由标签)等。
常用内置标签如下:
标签 | 描述 |
---|---|
{% for %} | 遍历输出上下文的内容 |
{% if %} | 对上下文进行条件判断 |
{% csrf_token %} | 生成csrf token的标签,用于防护跨站请求伪造攻击 |
{% url %} | 引用路由配置的地址,生成相应的路由地址 |
{% with %} | 将上下文名重新命名 |
{% load %} | 加载导入 Django的标签库 |
{% static %} | 读取静态资源的文件内容 |
{% extends xxx %} | 模板继承,xxx为模板文件名,使当前模板继承xxx模板 |
{% block xxx %} | 重写父类模板的代码 |
在for标签中,模板还提供了一些特殊的变量来获取for标签的循环信息,变量说明如下:
变量 | 描述 |
---|---|
forloop.counter | 获取当前循环的索引,从1开始计算 |
forloop.counter0 | 获取当前循环的索引,从0开始计算 |
forloop.revcounter | 索引从最大数开始递减,直到索引到1位置 |
forloop.revcounter0 | 索引从最大数开始递减,直到索引到0位置 |
forloop.first | 当遍历的元素为第一项时为真 |
forloop.last | 当遍历的元素为最后一项时为真 |
forloop.parentloop | 在嵌套的for循环中,获取上层for循环的forloop |
views不用更改,直接在modelEngine.html里写就好了。
py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板引擎测试</title>
</head>
<body>
<p>字符串测试:{{ msg1 }}</p>
<p>对象测试:对象姓名:{{ msg2.name }}、对象年龄:{{ msg2.age }}、对象性别:{{ msg2.sex }}、对象爱好:{{ msg2.hobby }}、对象:{{ msg2}}</p>
<p>元组测试:元组第一个{{ msg3.0 }}、元组第三个"{{ msg3.2 }}"、元组第四个{{ msg3.3 }}、元组:{{ msg3 }}</p>
<p>列表测试:列表第一个:{{ msg4.0 }}、列表第二个:{{ msg4.1 }}、列表第三个:{{ msg4.2 }}、列表第四个:{{ msg4.3 }}、列表:{{ msg4 }}</p>
<p>字典测试:字典键name值:{{ msg5.name }}、字典全部:{{ msg5 }}</p>
<h1>
模板标签测试
</h1>
<p>
if标签的用法:<br>
{% if msg1 == 'hello' %}
<a>msg1的值是hello</a>
{% elif msg1 == 'world' %}
<a>msg1的值是world</a>
{% else %}
<a>msg1的值是"{{ msg1 }}"</a>
{% endif %}
</p>
<p>
for标签的用法:<br>
{% for i in msg4 %}
{% if forloop.first %}
进入循环
{% endif %}<br>
这是for标签的第"{{ forloop.counter }}"次循环,变量的值:"{{ i }}"<br>
<a>循环倒计时:"{{ forloop.revcounter0 }}"</a><br>
{% if forloop.last %}
<a>循环结束</a>
{% endif %}
{% endfor %}<br>
</p>
<p>
url标签的用法:<br>
<a href = {% url 'modelengine' %}>点击跳转</a>
</p>
<p>
with标签的用法:<br>
<a>
{% with info=msg5 %}
info获得的值为:{{ info }}
{% endwith %}
</a>
</p>
</body>
</html>
运行测试http://127.0.0.1:8000/modelengine/
可以看到有if for url with标签的用法。注意写了for就要写end for,写了if也要写end if,甚至with也要搭配end with。这里的url标签的用法很精髓,方便后期部署。只需要在urls中其路径里加上name = 名称,后续herf = {%url '名称'%}即可,非常方便。
3.模板继承
Django模板继承是一个强大的工具,可以将通用页面元素(例如页眉、页脚、侧边栏等)分离出来,并在多个页面之间共享他们。
模板继承和 Python 语言中类的继承含义是一样的,在 Django 中模板只是一个文本文件,如 HTML。
模板继承是 Django 模板语言中最强大的部分。模板继承使你可以构建基本的"骨架"模板,将通用的功能或者属性写在基础模板中,也叫基类模板或者父模板。子模板可以继承父类模板,子模板继承后将自动拥有父类中的属性和方法,我们还可以在子模板中对父模板进行重写,即重写父模板中方法或者属性,从而实现子模板的定制。模板继承大大提高了代码的可重用性,减轻开发人员的工作量。
在模板继承中最常用了标签就是 {% block %} 与 {% extends %} 标签,其中 {% block% } 标签与 {% endblock %} 标签成对出现
我们新建一个基础模版base.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %}
这是基本页面
{% endblock %}
</title>
</head>
{% load static %}
<body>
<div id =header>
<img src="{% static '1.jpg' %}"/><br>
<a href="/helloWorld/">首页</a>
<a href="/helloWorld/student/list/">学生信息</a>
<a href="/helloWorld/extendtest/">继承测试</a>
<a href="/helloWorld/modelengine/">模板引擎测试</a><br>
--------------------------------------------------
</div>
<div id =content>
{% block content %}
这是基本页面
{% endblock %}
</div>
<div id =footer>
--------------------------------------------------<br>
版权所有 阿树梢
</div>
</body>
</html>
继承模板extendtest.html:
html
{% extends 'base.html' %}
{% block title %}
继承页面
{% endblock %}
{% block content %}
<a>这是继承base的页面</a>
{% endblock %}
可以看出来通过继承的模板的代码很方便,大大的减少了开发时间
在views和urls里加个函数和页面路径
views:
py
def extendtest(request):
return render(request, 'extendtest.html')
urls:
py
path('extendtest/',helloWorld.views.extendtest,name='extendtest')
运行测试访问http://127.0.0.1:8000/extendtest/
这里说几个注意点。标签block 要搭配endblock使用,block像是对象里可重写的属性方法。对于静态资源,可以先使用load static标签,再用{% static '文件名' %}作为它的地址。继承父类模板用extends标签来实现。
4. 过滤器
Django过滤器是一种用于在Django模板中处理数据的技术。过滤器的作用是可以对模板中的变量进行加工、过滤或格式化,返回一个新的值供模板使用。
过滤器作用是在变量输出时,对输出的变量值做进一步的处理。 我们可以使用过滤器来更改变量的输出显示。 过滤器跟模板标签一样,也是在模板中对函数进行调用 对输出的日期进行格式化处理,或者转换大小写字母等,这些都有对应的过滤器去处理它们。
过滤器的语法格式如下: {{ 变量 | 过滤器1:参数值1 | 过滤器2:参数值2 ... }}
常用内置过滤器如下:
过滤器 | 说明 |
---|---|
add | 加法 |
addslashes | 添加斜杠 |
capfirst | 首字母大写 |
center | 文本居中 |
cut | 切除字符 |
date | 日期格式化 |
default | 设置默认值 |
default_if_none | 为None设置默认值 |
dictsort | 字典排序 |
dictsortreversed | 字典反向排序 |
divisibleby | 整除判断 |
escape | 转义 |
escapejs | 转义js代码 |
filesizeformat | 文件尺寸人性化显示 |
first | 第一个元素 |
floatformat | 浮点数格式化 |
force_escape | 强制立刻转义 |
get_digit | 获取数字 |
iriencode | 转换IRI |
join | 字符列表链接 |
last | 最后一个 |
length | 长度 |
length_is | 长度等于 |
linebreaks | 行转换 |
linebreaksbr | 行转换 |
linenumbers | 行号 |
ljust | 左对齐 |
lower | 小写 |
make_list | 分割成字符列表 |
phone2numeric | 电话号码 |
pluralize | 复数形式 |
pprint | 调试 |
random | 随机获取 |
rjust | 右对齐 |
safe | 安全确认 |
safeseq | 列表安全确认 |
slice | 切片 |
slugify | 转换成ASCII |
stringformat | 字符串格式化 |
striptags | 去除HTML中的标签 |
time | 时间格式化 |
timesince | 从何时开始 |
timeuntil | 到何时多久 |
title | 所有单词首字母大写 |
truncatechars | 截断字符 |
truncatechars_html | 截断字符 |
truncatewords | 截断单词 |
truncatewords_html | 截断单词 |
unordered_list | 无序列表 |
upper | 大写 |
urlencode | 转义url |
urlize | url转成可点击的链接 |
urlizetrunc | urlize的截断方式 |
wordcount | 单词计数 |
wordwrap | 单词包裹 |
yesno | 将True,False和None,映射成字符串'yes','no','maybe' |
根据给定的格式格式化日期
格式字符 | 描述 | 示例输出 |
---|---|---|
a | 'a.m.' or 'p.m.' | 'a.m.' |
A | 'AM' or 'PM' | 'AM' |
b | 月份,文字形式,3个字幕库,小写 | 'jan' |
B | 未实现 | |
c | ISO 8601格式 | 2008-01-02T10:30:00.000123+02:00 |
d | 月的日子,带前导零的2位数字。 | 01'到'31' |
D | 周几的文字表述形式,3个字母。 | 'Fri' |
e | 时区名称 | ",'GMT,'-500',US/Eastern'等 |
E | 月份,分地区。 | |
f | 时间 | 1',1:30' |
g | 12小时格式,无前导零。 | "1'到'12' |
G | 24小时格式,无前导零。 | 0'到'23' |
h | 12小时格式。 | '01'到'12' |
H | 24小时格式。 | '00'到23' |
i | 分钟 | 00'到59' |
I | 夏令时间,无论是否生效。 | '1'或0 |
j | 没有前导零的月份的日子。 | '1'到"31' |
l | 星期几,完整英文名 | 'Friday' |
L | 布尔值是否是---个闰年。 | True或False |
m | 月,2位数字带前导零。 | '01'到'12' |
M | 月,文字,3个字母。 | "Jan" |
n | 月无前导零。 | '1'到'12' |
N | 美联社风格的月份缩写。 | 'Jan.' ,'Feb.','March','May' |
o | ISO-8601周编号 | '1999' |
O | 与格林威治时间的差,单位小时。 | '+0200' |
P | 时间为12小时 | 1:30 p.m.' , 'midnight' , 'noon' , '12:30 p.m.' |
r | RFC 5322格式化日期。 | 'Thu,21 Dec 2000 16:01:07+0200' |
s | 秒,带前导零的2位数字。 | '00'到59' |
S | 一个月的英文序数后缀,2个字符。 | 'st' ,'nd', 'rd'或'th' |
t | 给定月份的天数。 | 28 to 31 |
u | 微秒。 | 000000 to 999999 |
U | 自Unix Epoch以来的秒数(1970年1月1日00:00:00 UTC). | |
w | 星期几,数字无前导零。 | 'O'(星期日)至'6'(星期六) |
W | ISO-8601周数,周数从星期一开始。 | 1,53 |
y | 年份,2位数字。 | 99 |
Y | 年,4位数。 | '1999' |
z | ---年中的日子 | 0到365 |
Z | 时区偏移量,单位为秒。 | -43200到43200 |
过滤器主要就是用来格式化的工具,所以只需要用的时候来查表就行了
这里来给个实例
html
<p>
<h1>内置过滤器测试:</h1>
<a>
msg: {{ msg5 }}<br>
换成全部大写的方法1:用filter upper标签:
{% filter upper %}
{{ msg5 }}
{% endfilter %}<br>
方法2:
用过过滤器: {{ msg5|upper }}<br>
msg:{{ msg }},首字母大写capfirst: {{ msg|capfirst }}<br>
长度length: {{ msg|length }}
最后一个last: {{ msg|last }}<br>
date: {{ date }}<br>----->现在时间是:{{ date|date:"Y-m-d H:i:s" }}
</a>
</p>
注意一下,这里的date是需要事先在views中定义的。
py
from datetime import datetime
date = datetime.now()
运行测试一下,看看效果
jinja3模板引擎
Jinja是Python里面被广泛应用的模板引擎,最新版本3.1.3 它的设计思想来源于Django的模板引擎,并扩展了其语法和一系列强大的功能。其中最显著的是增加了沙箱执行功能和可选的自动转义功能,这对大多数应用的安全性来说是非常重要。此外,它还具备以下特性:
- 沙箱执行模式,模板的每个部分都在引擎的监督之下执行,模板将会被明确地标记在白名单或黑名单内,这样对于那些不信任的模板也可以执行。
- 强大的自动HTML转义系统,可以有效地阻止跨站脚本攻击。
- 模板继承机制,此机制可以使得所有模板具有相似一致的布局,也方便开发人员对模板进行修改和管理。
- 高效的执行效率,Jinja3引擎在模板第一次加载时就把源码转换成Python字节码,加快模板执行时间。
- 调试系统融合了标准的Python的TrackBack功能,使得模板编译和运行期间的错误能及时被发现和调试。
- 语法配置,可以重新配置Jinja3,使得它更好地适应LaTeX或JavaScript 的输出。官方文档手册,此手册指导设计人员更好地使用Jinja3引擎的各种方法。
- Django支持 Jinja3模板引擎的使用,由于Jinja3的设计思想来源于Django 的模板引擎,因此Jinja3的使用方法与 Django 的模板语法有相似之处。
开源主页:https://github.com/pallets/jinja
官方文档:https://jinja.palletsprojects.com/en/3.1.x/
1.安装与配置
我们用pip命令安装Jinja3
pip install Jinja2 -i https://pypi.tuna.tsinghua.edu.cn/simple
Jinja3安装成功后,接着在 Django里配置Jinja3模板。由于 Django的内置功能是使用 Django的模板引擎,如果将整个项目都改为Jinja3模板引擎,就会导致内置功能无法正常使用。在这种情况下,既要保证内置功能能够正常使用,又要使用Jinja3模板引擎,只能将两个模板引擎共存在同一个项目里。
首先我们在helloWorld项目库里新建Jinja3.py,用来定义环境参数;
py
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
env.globals.update(
{
'static': staticfiles_storage.url,
'url': reverse
}
)
return env
py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [BASE_DIR / 'templates']
,
'APP_DIRS': True,
'OPTIONS': {
'environment': 'helloWorld.Jinja3.environment'
},
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates', BASE_DIR / 'helloWorld/templates']
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
我们测试一下之前用不了的语法,字典[键]。测试结果如下:
这是jinja3支持的语法。
2.模板语法
尽管Jinja3的设计思想来源于Django 的模板引擎,但在功能和使用细节上,Jinja3比Django的模板引擎更为完善,而且Jinja3的模板语法在使用上与 Django的模板引擎存在一定的差异。 由于Jinja3有模板设计人员帮助手册(官方文档: https://jinja.palletsprojects.com/en/3.1.x/),并且官方文档对模板语法的使用说明较为详细,因此这里只讲述Jinja3与 Django模板语言的使用差异。
在遍历对象,列表,元组的时候,假如元素或者属性不存在,Jinja3会返回具体的报错信息:no such element
以及url函数用法不一样;在遍历for标签上,属性页不一样,内置的对象是loop
for函数模板变量:
Variable | Description |
---|---|
loop.index | 循环的当前迭代(索引从1开始) |
loop.index0 | 循环的当前迭代(索引从0开始) |
loop.revindex | 循环结束时的迭代次数(索引从1开始) |
loop.revindex0 | 循环结束时的迭代次数(索引从0开始) |
loop.first | 如果是第一次迭代,就为True |
loop.last | 如果是最后一次迭代,就为True |
loop.length | 序列中的项目数,即循环总次 |
loop.cycle | 辅助函数,用于在序列列表之间循环 |
loop.depth | 当前递归循环的深度,从1级开始 |
loop.depth0 | 当前递归循环的深度,从0级开始 |
loop.previtem | 上一次迭代中的对象 |
loop.nextitem | 下一次迭代中的对象 |
loop.changed(*val) | 若上次迭代的值与当前迭代的值不同,则返回True |
这里我就不写实例了,主要来说说两者语法的相同与不同点。
1.内置模板的forloop变为loop。forloop.counter变为loop.length
2.在遇到不存在的列表索引或字典键时,不像内置模板直接为空,而是报没找到对象。
3.内置模板的标签url和load static改为了更为简便的{{url'name')}}和{{static('文件名')}}
3.过滤器
Jinja3的过滤器与 Django内置过滤器的使用方法有相似之处,也是由管道符号"|"连接模板上下文和过滤器,但是两者的过滤器名称是不同的,而且过滤器的参数设置方式也不同。Jinja3常用过滤器如下表格:
过滤器 | 说明 |
---|---|
abs | 设置数值的绝对值 |
default | 设置默认值 |
escape | 转义字符,转成HTML的语法 |
first | 获取上下文的第一个元素 |
last | 获取上下文的最后一个元素 |
length | 获取上下文的长度 |
join | 功能与Python的join语法一致 |
safe | 将上下文转义处理 |
int | 将上下文转换为int类型 |
float | 将上下文转换为float类型 |
lower | 将字符串转换为小写 |
upper | 将字符串转换为大写 |
replace | 字符串的替换 |
truncate | 字符串的截断 |
striptags | 删除字符串中所有的HTML标签 |
trim | 截取字符串前面和后面的空白字符 |
string | 将上下文转换成字符串 |
wordcount | 计算长字符串的单词个数 |
具体使用可以参考下Jinja3官方文档( https://jinja.palletsprojects.com/en/3.1.x/templates/#filters )