【Django5】模板引擎

系列文章目录

第一章 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

然后我们找到项目配置settings.py:

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 )

相关推荐
沐霜枫叶2 小时前
解决pycharm无法识别miniconda
ide·python·pycharm
途途途途2 小时前
精选9个自动化任务的Python脚本精选
数据库·python·自动化
蓝染然2 小时前
jax踩坑指南——人类早期驯服jax实录
python
许野平2 小时前
Rust: enum 和 i32 的区别和互换
python·算法·rust·enum·i32
问道飞鱼2 小时前
【Python知识】Python进阶-什么是装饰器?
开发语言·python·装饰器
AI视觉网奇3 小时前
Detected at node ‘truediv‘ defined at (most recent call last): Node: ‘truediv‘
人工智能·python·tensorflow
GuYue.bing3 小时前
网络下载ts流媒体
开发语言·python
牛顿喜欢吃苹果4 小时前
linux创建虚拟串口
python
-Mr_X-4 小时前
FFmpeg在python里推流被处理过的视频流
python·ffmpeg
一个不秃头的 程序员4 小时前
代码加入SFTP JAVA ---(小白篇3)
java·python·github