Python Web开发 Jinja2模板引擎
在之前的文章中,简单介绍了Python Web开发框架Flask,知道了如何写个Hello World,但是距离用Flask开发真正的项目,还有段距离,现在我们目标更靠近一些 —— 学习下Jinja2模板。
模板的作用
模板是用来做什么的呢?模板是用来更高效地生成相应时的Html文本的,没有模板,可以手写,比如之前的hello world示例,写段html代码:
-
<h1>Hello world!</h1>
对于简单的练习还行,但对于规模大的,动态化程度高的项目来说,这样写就有些勉强了,即,不利于项目和产品化。那么模板有什么好处呢:
-
能让展现逻辑和业务逻辑 展示逻辑即UI,就是用来给用户看和操作的,业务逻辑是业务规则,比如什么条件可以注册,什么权限能考到什么。模板将展现逻辑封装起来,业务逻辑写在视图函数中。
-
能使项目更易维护 由于展现逻辑和业务逻辑的分离,它们可以由不同的开发人员来维护,不会有代码冲突的问题
-
使项目更加安全 在做交互式开发中,有个原则: 永远不要相信用户的输入,因为恶意用户可能通过输入来注入(关于注入以后有机会可以单独聊聊),而模板在一定程度上会防注入,例如用户输入一点html代码作为输入,默认情况下模板会将其替换为网络安全字符,以防止恶意注入。
-
能提高开发效率 有了模板,相当于一个展示逻辑的函数,所以就可以被复用,可以用在不同的视图函数中,也可以用在不同的项目中
思考下:上面提到的展现逻辑和业务逻辑,为什么不直接说成前台和后台呢? 如果你有答案和想法,欢迎留言讨论。
Jinja2模板引擎
Jinja2是Flask框架默认支持的模板引擎,并不是唯一也不是最好(因人而异,没有最好)模板引擎,不同的Web框架,比如Django、Nodejs等都有自己的模板引擎,甚至一些程序员自己实现的模板引擎(我就这么干过),但大体思路是一样的,都是要将数据替换或者转换到,用特殊格式标记了位置的模板中,以合成动态的html,这种技术不新鲜,在之前的打印模板,如水晶报表里就有,无非就是标记和语法不同而已,所以要举一反三。
引入渲染函数
像其他功能一样,要使用模板引擎,先引入
-
from flask import render_template
注意:要将将模板文件放置在项目根目录(即
print(__file__)显示的路径)下的templates文件夹中
例如模板文件 hello.html为:
-
<h1>Hello {{ name }} </h1>
视图函数可以写成:
-
@app.route('/user/<name>') -
def index(name): -
return render_template('hello.html', name=name)
Flask提供的 render_template函数把Jinja2模板引擎集成到了程序中。render_template函数第一个参数是模板的文件名,随后的参数都是键值对,表示模板中变量的对应的真实值,在上面代码中,模板会接收到一个名为 name的变量
变量
模板文件就是普通的文本文件,然后将需要替换的部分用双大括号( {{}})标记出来,双大括号中,表示要替换的变量名,这个变量支持基本数据类型,以及列表、词典、对象和元组。如模板 template.html:
-
<p> A value form a string: {{ name }}.</p> -
<p> A value form a int: {{ myindex }}.</p> -
<p> A value form a list: {{ mylist[3]] }}.</p> -
<p> A value form a list, with a variable index: {{ mylist[myindex] }}.</p> -
<p> A value form a dictionary: {{ mydict['key'] }}.</p> -
<p> A value form a tuple: {{ mytuple }}.</p> -
<p> A value form a tuple by index: {{ mytuple[myindex] }}.</p>
视图函数代码:
-
@app.route('/template/') -
def template(): -
name = 'Jinja2 模板引擎' -
myindex = 1 -
mylist = [1,2,3,4] -
mydict = { -
"key": 'age', -
"value": '25' -
} -
mytuple = (1,2,3,4) -
return render_template('template.html', name=name, myindex=myindex, mylist=mylist, mydict=mydict, mytuple=mytuple)
显示结果:

过滤器
有些时候需要对要在模板中替换的值做一些特殊处理,比如首字母大写,去掉前后空格等等,有种选择就是使用过滤器。
说明
Jinjia2模板引擎中,过滤器类似于Linux命令中的管道,例如将字符串变量的首字母大写
-
<h1>{{ name | capitalize}}</h1>
过滤器可以拼接,和linux的管道命令一样,如对值进行全部变大写,并且去除前后空白字符:
-
<h1>{{ name | upper | trim }}</h1>
如上代码,过滤器和变量之间用管道符号 | 相连,相当于对变量值作进一步加工。
一些常用的过滤器
| 过滤器 | 说明 |
|---|---|
| safe | 渲染是不转义 |
| capitalize | 首字母大写 |
| lower | 所有字母小写 |
| upper | 所有字母大写 |
| title | 值中每个单词首字母大写 |
| trim | 删除首位空白字符 |
| striptags | 渲染时删除掉值中所有HTML标签 |
注意:safe过滤器,默认情况下,处于安全考虑,Jinja2会转义所有变量,例如一个变量的值为 <h1>Hello</h1>, Jinja2会将其渲染成 <h1>Hello</>,浏览器会显示出原本的值,但是不会解释。如果需要浏览器解释的话,可以使用 safe 过滤器 例如模板文件 html.html为:
-
<h1>{{ html | safe }}</h1>
视图函数为:
@app.route('/html')
def html():
return render_template('html.html', html='<b>bob</b>')
注意:千万别在不可信的值上使用 safe 过滤器,例如用户在表单上输入的文本。
还有一些有用的过滤器
-
default,可以当变量未定义时,提供默认值,如果想将false、False和空(none)视为未定义,需要提供第二个参数为true{% raw %}当变量
name的未定义时,上下两个显示效果一样,当值为none时,上面会显示Hellonone!, 而下面的会显示Helloworld!-
<!-- 提供默认值过滤器 --> -
<h1>Hello {{ name | default('world') }}!</h1> -
<!-- 将false、False和空(none)视为未定义的默认值过滤器 --> -
<h1>Hello {{ name | default('world', true)! }}</h1>
-
-
列表过滤器
min,max, 得到列表中的最小值或最大值
自定义过滤器
过滤器虽然有很多,但总有不满足需求的时候,例如首行文字缩进、将金额转化为中文的大写等等。过滤器实质就是个函数,所以,第一定义一个过滤器函数,第二,注册到Jinjia2的过滤器中。
#自定义过滤器函数
def mylen(arg):#实现一个可以求长度的函数return len(arg)
def interval(test_str, start, end):#返回字符串中指定区间的内容return test_str[int(start):int(end)]
#注册过滤器
env = app.jinja_env
env.filters['mylen'] = mylen
env.filters['interval'] = interval@app.route('/myfilter')
def myfilter():return render_template('myfilter.html', phone = '135645xxx623')
模板
-
<h1>电话号码是:{{ phone }}, 长度为:{{ phone | mylen }},运营商号:{{ phone | interval(0,3) }}</h1>
过滤器注册代码还可以写在初始化代码
__init__.py中
控制结构
很多时候,需要更智能的模板渲染,即能给渲染编程,比如男生一个样式,女生一样样式,控制结构指令需要用指令标记来指定,下面介绍下一些简单的控制结构
条件
即在模板中用 if-else控制结构
{% if gender=='male' %}
Hello, Mr {{ name }}
{% else %}
Hello, Ms {{ name }}
{% endif %}
视图函数
@app.route('/hello2/<name>/<gender>')
def hello2(name, gender):
return render_template('hello2.html', name=name, gender=gender)
在控制结构里,代码语法同 python
循环
循环对于渲染列表,很有帮助,循环的标记是 for。例如奖列表的内容显示在 ul中
<ul>
{% for name in names %}
<li>{{ name }} </li>
{% endfor %}
</ul>
例如给定一个学生列表,将其用无序列表 ul显示出来
宏——模板中的函数
模板中可以定义宏,相当于定义了一个函数,可以重复使用,让逻辑更清晰。首先,定义一个宏:
{% macro render_name(name) %}
<li>{{ name }}</li>
{% endmacro %}
{% endraw %} 然后使用宏, 例如将循环结构的例子中,显示名称的地方,改为调用宏 {% raw %}
<ul>
{% for name in names %}
{{ render_name(name) }}
{% endfor %}
</ul>
调用宏,和调用函数是一样的,不过要将代码写在 {{}}双大括号内。一般我们会将宏存在单独的文件中,以便复用,在需要用到宏的地方,引用就好了
{% import 'mymarco.html' as macros %}
<ul>
{% for name in names %}
{{ macros.render_name(name) }}
{% endfor%}
</ul>
如上所述,用improt引入宏定义文件,通过as指定别名,和python的模块引入一样。指定别名是一个良好的编程习惯,可以将一个复杂的东西形象化,同时像一个命名空间一样,有效的避免冲突。
include
另外可以将多个模板片段写入一个单独文件,再包含( include)在所有模板中,以提高开发效率:
-
{% include 'common.html' %}
include进来的文件,相当于将文件中的内容复制到 include的位置,所以自使用之前需要考虑仔细
模板继承
如果觉得 include过于呆板,灵活性差,Jinja2模板引擎还有更高级的功能——继承。类似于Python代码中类的继承,一起看看。首先定义一个基类, base.html:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">{% block head %}<title>{% block title %}{% endblock %} - My Application</title>{% endblock %}
</head>
<body>{% block body %}<h3>这是基类的内容</h3>{% endblock %}
</body>
</html>
其中的 block标签,定义了可以被子类重构(替换)的部分,每个 blcok标签,需要指定一个特殊的名称,例如 head、 title等,以便子类用特定的名称来重构。另外 block标签需要有结束标签 endblock,类似于类C语言中的大括号,当然 block标签也可以嵌套。接下来,定义一个子类模板 hello3.html:
<!DOCTYPE html>
<html lang="en">
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}{{ super()}}<style></style>
{% endblock %}
{% block body %}{{ super()}}<h4>这是子类的内容Hello world</h4>
{% endblock %}
</html>
@app.route('/hello3')
def hello3():return render_template('hello3.html')
效果如图所示:

通过 extends标记来指定需要继承的基类,然后用 block标记来设置子类需要替换调基类中的内容,只要 block指定的名称一样就行。另外,如不需要完全替换调基类的内容,可以在子类 block中,调用 super方法,以获取基类在此名称下的内容,这样就能达到更号的灵活性。
总结
今天介绍了Jinja2模板引擎的基本用法和特点,期望通过不同的特点,让你了解到模板的基本用法,以便更快的使用和进一步学习更深入的内容。另外,想通过Jinja2模板引擎,说明模板的基本特征,以便触类旁通、举一反三,更快的学习其他优秀的模板, 同时也想说明,模板不仅仅可以用在Web的开发中,还可以用在自动化编码、测试等众多领域。
相关文章:
Python Web开发 Jinja2模板引擎
在之前的文章中,简单介绍了Python Web开发框架Flask,知道了如何写个Hello World,但是距离用Flask开发真正的项目,还有段距离,现在我们目标更靠近一些 —— 学习下Jinja2模板。 模板的作用 模板是用来做什么的呢&…...
ubuntu上安装mosquitto服务
1、mosquitto是什么 Mosquitto 项目最初由 IBM 和 Eurotech 于 2013 年开发,后来于 2016 年捐赠给 Eclipse 基金会。Eclipse Mosquitto 基于 Eclipse 公共许可证(EPL/EDL license)发布,用户可以免费使用。作为全球使用最广的 MQTT 协议实现之一 &#x…...
嵌入式开发学习(STC51-9-led点阵)
内容 点亮一个点; 显示数字; 显示图像; LED点阵简介 LED 点阵是由发光二极管排列组成的显示器件 通常应用较多的是8 * 8点阵,然后使用多个8 * 8点阵可组成不同分辨率的LED点阵显示屏,比如16 * 16点阵可以使用4个8 *…...
RedisTemplate.opsForZSet()用法简介并举例
RedisTemplate.opsForZSet()是RedisTemplate类提供的用于操作ZSet类型(有序集合)的方法。它可以用于对Redis中的ZSet数据结构进行各种操作,如添加成员、获取成员、删除成员等。 下面是一些常用的RedisTemplate.opsForZSet()方法及其用法示例…...
Java个人博客系统--基于Springboot的设计与实现
目录 一、项目概述 应用技术 接口实现: 数据库定义: 数据库建表: 博客表数据库相关操作: 添加项⽬公共模块 加密MD5 页面展示:http://121.41.168.121:8080/blog_login.html 项目源码:https://gitee…...
在jupyter中下载数据集失败及解决方法(以IMDB为例)
在IMDB数据集下载时,由于网络原因下载失败,报错如下: Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz ConnectionResetError Traceback (most recent call last) … Exception: URL fetch f…...
【设计模式】-工厂方法模式
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它通过定义一个用于创建对象的接口,但是将具体对象的创建推迟到子类中。这样,子类可以决定要实例化的对象类型。工厂方法模式提供了一种方式,通…...
H7-TOOL的高速DAPLINK用于新版STM32CubeIDE V1.13及其以上版本的超简单实现方法(2023-08-08)
之前分享了一个方法,太繁琐了,H7-TOOL群的群友提供了一个方法,实现非常简单。1、使用STM32CubeMX或者自己创建一个STM32CubeIDE工程后,设置这两个地方即可: 配置调试器,设置完毕记得点击右下角的Apply 2、然…...
成功解决ubuntu-22.04的sudo apt-get update一直卡在【0% [Waiting for headers]】
成功解决ubuntu-22.04的sudo apt-get update一直卡在【0% [Waiting for headers]】 问题描述解决方案 问题描述 在下载安装包的时候一直卡在0% [Waiting for headers],报错信息如下: Get:1 file:/var/cudnn-local-repo-ubuntu1804-8.5.0.96 InRelease […...
openLayers实战(一):vue项目中的离线地图引入
最近的项目涉及到离线地图的操作,查阅社区文章,决定使用openLayersvue离线地图的方式进行开发,前期基础引入操作完全参考掘金文章,非常优秀全面的文章。 openlayers 实战离线地图 - 掘金 此外,开发过程的地图操作可参考…...
如何构造一个安全的单例?
为什么要问这个问题? 我们知道,单例是一种很常用的设计模式,主要作用就是节省系统资源,让对象在服务器中只有一份。但是实际开发中可能有很多人压根没有写过单例这种模式,只是看过或者为了面试去写写demo熟悉一下。那…...
单片机开发 esp8266
一、固件界面 二、项目介绍 固件名称:esp8266-universalboard v1.0 提供商: 半条虫(466814195) 下载:esp8266-universalboard.bin 源码地址:Gitlab...
Linux 查看版本和用户权限提升实践心得
文章目录 linux (Ubuntu内核)查看版本版本信息解释内置yum工具?用户权限提升操作步骤 查看deepin系统的版本和其debian的版本遇到的问题:deepin-release文件不存在 linux (Ubuntu内核)查看版本 使用lsb_release命令: lsb_release -a该命令将…...
多线程编程5:线程同步和进程通信(C++11和linux)
常见的线程同步 linux: 互斥锁:实现共享资源的串行访问,有三个版本普通锁(默认属性),检错锁(可以防止相同线程重复加锁)和递归锁(相同线程可以重复加锁)条件变量:配合互斥锁使用,实现线程之间的通信&#…...
tensorrt官方int8量化方法汇总
原理及操作 量化的基本原理及流程可参看懂你的神经网络量化教程:第一讲、量化番外篇、TensorRT中的INT8、tensorRT int8量化示例代码 Tensorrt 方式1:trtexec(PTQ的一种) int8量化 trtexec --onnxXX.onnx --saveEnginemodel.…...
21、p6spy输出执行SQL日志
文章目录 1、背景2、简介3、接入3.1、 引入依赖3.2、修改database参数:3.3、 创建P6SpyLogger类,自定义日志格式3.4、添加spy.properties3.5、 输出样例 4、补充4.1、参数说明 1、背景 在开发的过程中,总希望方法执行完了可以看到完整是sql语…...
实力认证!TDengine 入选 Gartner 中国数据分析与人工智能技术成熟度曲线
近日,国际权威研究机构 Gartner 发布了《2023 年中国数据分析及人工智能技术成熟度曲线》(即《Hype Cycle for Data, Analytics and AI in China, 2023》)报告,TDengine 成功入选实时数据管理领域代表产品。 作为评估全球新技术成…...
如何将jar包部署到宝塔
尝试多种方式上传,但启动一直失败,这种方式亲测是好使的 项目内修改位置 在pom.xml文件中将mysql的scope改成provided,如果是固定的版本号会出现问题 之后就可以打包啦,直接点击maven中的package 找到打包文件的位置ÿ…...
el-tree-select那些事
下拉菜单树形选择器 用于记录工作及日常学习涉及到的一些需求和问题 vue3 el-tree-select那些事 1、获取el-tree-select选中的任意层级的节点对象 1、获取el-tree-select选中的任意层级的节点对象 1-1数据集 1-2画面 1-3代码 1-3-1画面代码 <el-tree-selectv-model"s…...
分布式任务调度框架之开山鼻祖:Quartz
1.简介 最近我司上线使用了分布式任务调度框架:XXL-JOB,方便对任务的管理控制。本来一开始就想讲述一下该框架,但是在学习了解过程中发现该框架式基于Quartz思想开发实现的,Quartz 是一个很火的开源任务调度框架,完全…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
