Python Web开发 Jinja2模板引擎

news2024/11/25 18:40:48

在之前的文章中,简单介绍了Python Web开发框架Flask,知道了如何写个Hello World,但是距离用Flask开发真正的项目,还有段距离,现在我们目标更靠近一些 —— 学习下Jinja2模板。

模板的作用

模板是用来做什么的呢?模板是用来更高效地生成相应时的Html文本的,没有模板,可以手写,比如之前的hello world示例,写段html代码:

  1. <h1>Hello world!</h1>

对于简单的练习还行,但对于规模大的,动态化程度高的项目来说,这样写就有些勉强了,即,不利于项目和产品化。那么模板有什么好处呢:

  1. 能让展现逻辑和业务逻辑 展示逻辑即UI,就是用来给用户看和操作的,业务逻辑是业务规则,比如什么条件可以注册,什么权限能考到什么。模板将展现逻辑封装起来,业务逻辑写在视图函数中。

  2. 能使项目更易维护 由于展现逻辑和业务逻辑的分离,它们可以由不同的开发人员来维护,不会有代码冲突的问题

  3. 使项目更加安全 在做交互式开发中,有个原则: 永远不要相信用户的输入,因为恶意用户可能通过输入来注入(关于注入以后有机会可以单独聊聊),而模板在一定程度上会防注入,例如用户输入一点html代码作为输入,默认情况下模板会将其替换为网络安全字符,以防止恶意注入。

  4. 能提高开发效率 有了模板,相当于一个展示逻辑的函数,所以就可以被复用,可以用在不同的视图函数中,也可以用在不同的项目中

思考下:上面提到的展现逻辑业务逻辑,为什么不直接说成前台后台呢? 如果你有答案和想法,欢迎留言讨论。

Jinja2模板引擎

Jinja2是Flask框架默认支持的模板引擎,并不是唯一也不是最好(因人而异,没有最好)模板引擎,不同的Web框架,比如Django、Nodejs等都有自己的模板引擎,甚至一些程序员自己实现的模板引擎(我就这么干过),但大体思路是一样的,都是要将数据替换或者转换到,用特殊格式标记了位置的模板中,以合成动态的html,这种技术不新鲜,在之前的打印模板,如水晶报表里就有,无非就是标记和语法不同而已,所以要举一反三。

引入渲染函数

像其他功能一样,要使用模板引擎,先引入

  1. from flask import render_template

注意:要将将模板文件放置在项目根目录(即 print(__file__)显示的路径)下的 templates文件夹中

 

 

例如模板文件 hello.html为:

  1. <h1>Hello {{ name }} </h1>

视图函数可以写成:

  1. @app.route('/user/<name>')

  2. def index(name):

  3. return render_template('hello.html', name=name)

Flask提供的 render_template函数把Jinja2模板引擎集成到了程序中。render_template函数第一个参数是模板的文件名,随后的参数都是键值对,表示模板中变量的对应的真实值,在上面代码中,模板会接收到一个名为 name的变量

变量

模板文件就是普通的文本文件,然后将需要替换的部分用双大括号( {{}})标记出来,双大括号中,表示要替换的变量名,这个变量支持基本数据类型,以及列表、词典、对象和元组。如模板 template.html:

  1. <p> A value form a string: {{ name }}.</p>

  2. <p> A value form a int: {{ myindex }}.</p>

  3. <p> A value form a list: {{ mylist[3]] }}.</p>

  4. <p> A value form a list, with a variable index: {{ mylist[myindex] }}.</p>

  5. <p> A value form a dictionary: {{ mydict['key'] }}.</p>

  6. <p> A value form a tuple: {{ mytuple }}.</p>

  7. <p> A value form a tuple by index: {{ mytuple[myindex] }}.</p>

视图函数代码:

  1. @app.route('/template/')

  2. def template():

  3. name = 'Jinja2 模板引擎'

  4. myindex = 1

  5. mylist = [1,2,3,4]

  6. mydict = {

  7. "key": 'age',

  8. "value": '25'

  9. }

  10. mytuple = (1,2,3,4)

  11. return render_template('template.html', name=name, myindex=myindex, mylist=mylist, mydict=mydict, mytuple=mytuple)

显示结果:

图片

过滤器

有些时候需要对要在模板中替换的值做一些特殊处理,比如首字母大写,去掉前后空格等等,有种选择就是使用过滤器。

说明

Jinjia2模板引擎中,过滤器类似于Linux命令中的管道,例如将字符串变量的首字母大写

  1. <h1>{{ name | capitalize}}</h1>

过滤器可以拼接,和linux的管道命令一样,如对值进行全部变大写,并且去除前后空白字符:

  1. <h1>{{ name | upper | trim }}</h1>

如上代码,过滤器和变量之间用管道符号 | 相连,相当于对变量值作进一步加工。

一些常用的过滤器

过滤器说明
safe渲染是不转义
capitalize首字母大写
lower所有字母小写
upper所有字母大写
title值中每个单词首字母大写
trim删除首位空白字符
striptags渲染时删除掉值中所有HTML标签

注意:safe过滤器,默认情况下,处于安全考虑,Jinja2会转义所有变量,例如一个变量的值为 <h1>Hello</h1>, Jinja2会将其渲染成 &lt;h1&gt;Hello&lt;/&gt;,浏览器会显示出原本的值,但是不会解释。如果需要浏览器解释的话,可以使用 safe 过滤器 例如模板文件 html.html为:

  1. <h1>{{ html | safe }}</h1>

视图函数为:

  1. @app.route('/html')

  2. def html():

  3. return render_template('html.html', html='<b>bob</b>')

注意:千万别在不可信的值上使用 safe 过滤器,例如用户在表单上输入的文本。

还有一些有用的过滤器

  • default,可以当变量未定义时,提供默认值,如果想将 falseFalse和空( none)视为未定义,需要提供第二个参数为 true{% raw %}

    当变量 name的未定义时,上下两个显示效果一样,当值为 none时,上面会显示 Hellonone!, 而下面的会显示 Helloworld!

    1. <!-- 提供默认值过滤器 -->

    2. <h1>Hello {{ name | default('world') }}!</h1>

    3. <!-- 将false、False和空(none)视为未定义的默认值过滤器 -->

    4. <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')

模板

  1. <h1>电话号码是:{{ phone }}, 长度为:{{ phone | mylen }},运营商号:{{ phone | interval(0,3) }}</h1>

过滤器注册代码还可以写在初始化代码 __init__.py

控制结构

很多时候,需要更智能的模板渲染,即能给渲染编程,比如男生一个样式,女生一样样式,控制结构指令需要用指令标记来指定,下面介绍下一些简单的控制结构

条件

即在模板中用 if-else控制结构

  1. {% if gender=='male' %}

  2. Hello, Mr {{ name }}

  3. {% else %}

  4. Hello, Ms {{ name }}

  5. {% endif %}

视图函数

  1. @app.route('/hello2/<name>/<gender>')

  2. def hello2(name, gender):

  3. return render_template('hello2.html', name=name, gender=gender)

在控制结构里,代码语法同 python

循环

循环对于渲染列表,很有帮助,循环的标记是 for。例如奖列表的内容显示在 ul

  1. <ul>

  2. {% for name in names %}

  3. <li>{{ name }} </li>

  4. {% endfor %}

  5. </ul>

例如给定一个学生列表,将其用无序列表 ul显示出来

宏——模板中的函数

模板中可以定义宏,相当于定义了一个函数,可以重复使用,让逻辑更清晰。首先,定义一个宏:

  1. {% macro render_name(name) %}

  2. <li>{{ name }}</li>

  3. {% endmacro %}

{% endraw %} 然后使用宏, 例如将循环结构的例子中,显示名称的地方,改为调用宏 {% raw %}

  1. <ul>

  2. {% for name in names %}

  3. {{ render_name(name) }}

  4. {% endfor %}

  5. </ul>

调用宏,和调用函数是一样的,不过要将代码写在 {{}}双大括号内。一般我们会将宏存在单独的文件中,以便复用,在需要用到宏的地方,引用就好了

  1. {% import 'mymarco.html' as macros %}

  2. <ul>

  3. {% for name in names %}

  4. {{ macros.render_name(name) }}

  5. {% endfor%}

  6. </ul>

如上所述,用improt引入宏定义文件,通过as指定别名,和python的模块引入一样。指定别名是一个良好的编程习惯,可以将一个复杂的东西形象化,同时像一个命名空间一样,有效的避免冲突。

include

另外可以将多个模板片段写入一个单独文件,再包含( include)在所有模板中,以提高开发效率:

  1. {% 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标签,需要指定一个特殊的名称,例如 headtitle等,以便子类用特定的名称来重构。另外 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的开发中,还可以用在自动化编码、测试等众多领域。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/849509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C 语言高级3--函数指针回调函数,预处理,动态库的封装

目录 1.函数指针和回调函数 1.1 函数指针 1.1.1 函数类型 1.1.2 函数指针(指向函数的指针) 1.1.3 函数指针数组 1.1.4 函数指针做函数参数(回调函数) 2.预处理 2.1 预处理的基本概念 2.2 文件包含指令(#include) 2.2.1 文件包含处理 2.2.2 #incude<>和#include&q…

数据结构:栈的实现(C实现)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》 文章目录 前言一、栈的实现思路1. 结构的定义2. 初始化栈(StackInit)3. 入栈(StackPush)4. 出栈(StackPop)5. 获取栈顶元素(StackTop)6. 检查栈是否为空(StackEmpty)7. 销毁栈(StackDestroy) 二、…

踩坑 视觉SLAM 十四讲第二版 ch13 编译及运行问题

一、安装Geset 库 sudo apt-get install libgtest-dev cd /usr/src/gtest sudo mkdir build cd build sudo cmake .. //一定要以sudo的方式运行&#xff0c;否则没有写入权限 sudo make //这个也一样要以sudo的方式 sudo cp libgtest*.a /usr/local/lib //将生成…

python表白代码大全可复制,python表白代码大全简单

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python表白代码大全可复制&#xff0c;python表白程序代码完整版&#xff0c;现在让我们一起来看看吧&#xff01; 今天是20230520&#xff0c;有人说&#xff1a;5代表的是人生五味&#xff0c;酸甜苦辣咸&#xff1b;…

设备管理平台:采用以可靠性为中心的维护策略的优势

在如今的工业领域&#xff0c;以可靠性为中心的维护策略正逐渐成为企业数字化转型的核心。无论是混合还是离散自动化应用&#xff0c;优化维护和工作流程实践已经成为提高利润、降低停机时间、增强运营和生产性能的不可或缺的一环。在这个过程中&#xff0c;设备管理系统与物联…

Harbor部署--使用 Harbor 安装包

一、Harbor安装准备条件 这里以 harbor 2.8.3 版本为例 1.1 硬件要求 Harbor 安装对硬件资源CPU、内存和硬盘的要求如下表&#xff1a; 资源 最小要求 推荐配置 CPU 2 CPU 4 CPU Mem 4 GB 8 GB Disk 40 GB 160 GB 使用如下命令分别查看服务器的物理CPU和逻辑CPU个数…

LCD1602相关

一.概述 LCD1602是一种工业字符型液晶&#xff0c;能够同时显示16*02即32字符&#xff08;16列2行&#xff09; 二.引脚接口说明表 第 1 脚 : VSS 为电源地 第 2 脚 : VDD 接 5V 正电源 第 3 脚 : VL 为液晶显示器对比度调整端 , 接正电源时对比度最弱&#xff…

第三章 图论 No.8最近公共祖先lca, tarjan与次小生成树

文章目录 lcaTarjan板子题&#xff1a;1172. 祖孙询问lca或tarjan&#xff1a;1171. 距离356. 次小生成树352. 闇の連鎖 lca O ( m l o g n ) O(mlogn) O(mlogn)&#xff0c;n为节点数量&#xff0c;m为询问次数&#xff0c;lca是一种在线处理询问的算法 自己也是自己的祖先 倍…

XML方式AOP快速入门XML方式AOP配置详解

目录 1.XML方式AOP快速入门 1&#xff1a;导入AOP相关坐标 2&#xff1a;准备目标类&#xff0c;准备增强类&#xff0c;并配置给Spring管理 3&#xff1a;配置切点表达式&#xff08;那些方法要被增强&#xff09; 4&#xff1a;配置织入&#xff08;切点被哪些方法增强&…

漫画算法做题笔记

诸神缄默不语-个人CSDN博文目录 哦这是我三年前写的&#xff0c;我现在Java语法都快忘光了…… 反正之前的博文也发一下好了。这个因为我当年是用有道云笔记而不是直接用CSDN编辑器写的&#xff0c;所以后面有些内容写乱了&#xff0c;因为我现在猛的一看有点看不懂&#xff0…

一文读懂|RDMA原理

什么是DMA DMA全称为Direct Memory Access&#xff0c;即直接内存访问。意思是外设对内存的读写过程可以不用CPU参与而直接进行。我们先来看一下没有DMA的时候&#xff1a; 无DMA控制器时I/O设备和内存间的数据路径 假设I/O设备为一个普通网卡&#xff0c;为了从内存拿到需要…

事务的隔离级别与Spring事务的传播机制

目录 事务的隔离性 事务的隔离级别 读未提交 读已提交 可重复读 串行化 Spring事务的传播机制 支持当前事务 不支持当前事务 嵌套事务 事务的隔离性 事务的隔离性是事务的四大特性之一&#xff0c;数据库允许多个事务并发操作数据&#xff0c;为了尽可能地避免并发操…

【JAVA】-【IO流】

文章目录 FileReader读入数据的基本操作FileReader中使用reader()FileWrite写出数据的操作使用FileInputStream、FileOutputStream操作图片缓冲流&#xff08;字节型&#xff09;实现非文本文件的复制 复制文本文件也可以使用字节流&#xff0c;但是不要在内存中读出来&#xf…

【Matlab】Elman神经网络遗传算法(Elman-GA)函数极值寻优——非线性函数求极值

往期博客&#x1f449; 【Matlab】BP神经网络遗传算法(BP-GA)函数极值寻优——非线性函数求极值 【Matlab】GRNN神经网络遗传算法(GRNN-GA)函数极值寻优——非线性函数求极值 【Matlab】RBF神经网络遗传算法(RBF-GA)函数极值寻优——非线性函数求极值 本篇博客将主要介绍Elman神…

【Spring Boot】Spring Boot项目的创建和文件配置

目录 一、为什么要学Spring Boot 1、Spring Boot的优点 二、创建Spring Boot项目 1、创建项目之前的准备工作 2、创建Spring Boot项目 3、项目目录的介绍 4、安装Spring Boot快速添加依赖的插件 5、在项目中写一个helloworld 三、Spring Boot的配置文件 1、配置文件的…

opencv基础48-绘制图像轮廓并切割示例-cv2.drawContours()

绘制图像轮廓&#xff1a;drawContours函数 在 OpenCV 中&#xff0c;可以使用函数 cv2.drawContours()绘制图像轮廓。该函数的语法格式是&#xff1a; imagecv2.drawContours( image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]…

mousedown拖拽功能(vue3+ts)

因为项目有rem适配&#xff0c;使用第三方插件无法处理适配问题&#xff0c;所有只能自己写拖拽功能了 拖拽一般都会想到按下&#xff0c;移动&#xff0c;放开&#xff0c;但是本人亲测&#xff0c;就在div绑定一个按下事件就行了&#xff08;在事件里面写另外两个事件&#x…

前端架构师的具体职责范围(合集)

前端架构师的具体职责范围1 职责&#xff1a; 1、前端技术选型、架构搭建、制定前端开发规范&#xff0c;并编制相关文档 2、负责搭建前端框架、通用组件方案制定、性能优化相关工作; 3、维护和升级本地开发环境&#xff0c;提高开发效率&#xff0c;提升开发质量; 4、推动…

【深度学习注意力机制系列】—— ECSKNet注意力机制(附pytorch实现)

SKNet&#xff08;Selective Kernel Network&#xff09;是一种用于图像分类和目标检测等任务的深度神经网络架构&#xff0c;其核心创新是引入了选择性的多尺度卷积核&#xff08;Selective Kernel&#xff09;以及一种新颖的注意力机制&#xff0c;从而在不增加网络复杂性的情…

2.安装Docker-ce

一、删除之前安装的docker(若之前未安装过&#xff0c;此步骤省略…) 进入centos根目录执行以下命令&#xff08;\ 是linux系统种命令换行符&#xff0c;如果命令过长&#xff0c;可以用\来换行&#xff09; yum remove docker \ docker-client \ docker-client-latest \ doc…