Flask 的 jinja2 模板
还记的 “第一个 Flask 程序”这一小节中我们直接在 Python 源程序中直接返回一段 HTML 字符串,就可以在浏览器中看到效果,但是如果我们的 HTML 特别复杂呢?我们还能使用这样的形式吗?
答案是不行的,如果你的 HTML 特别复杂仍然使用这样的方法会造成你的后端程序非常的混乱,Python 代码和 HTML 代码混杂在一起,程序的可阅读行非常差。
本节课我们将会使用一个叫做 Jinja2 的东西来解决上面提到的问题。
Tips:本节课所有的代码已经上传到了 Github,可以点击这里进行下载。
1. 模板简介
1.1 简介
浏览器访问网站时,服务端通常会返回一个包含各类信息的 html 页面。因为网页是动态的,页面中的某些信息需要根据不同的情况来进行调整,比如对登录和未登录用户显示不同的信息,所以页面需要在用户访问时根据程序逻辑动态生成。
把包含变量和运算逻辑的 html 或其他格式的文本叫做模板,执行这些变量替换和逻辑计算工作的过程被称为渲染,在 Flask 中,这个工作由模板渲染引擎——jinja2 来完成。
1.2 一个具体的例子
以下是一个 jinja2 的模板,它对登录和未登录用户显示不同的信息:
<html>
{% if login %}
<p>你好,{{name}}</p>
{% else %}
<a href='/login'>登录</a>
{% endif %}
</html>
如果用户已经登录:变量 login 为真、变量 name 为 tom,模板被渲染成如下的 html 文件:
<html>
<p>你好,tom</p>
</html>
如果用户没有登录:变量 login 为假,模板被渲染成如下的 html 文件:
<html>
<a href='/login'>登录</a>
</html>
2. 在 Flask 中使用模板
本节通过一个具体的例子讲解如何在 Flask 中使用 jinja2 模板。
2.1 目录结构
程序包含有两个源文件: app.py
和 index.html,目录结构如下:
app.py
是 Flask 程序,将渲染后的模板返回给浏览器;templates 是存放模板的目录,它和 app.py 位于相同的目录;templates/index.html 是模板文件。
2.2 编写 app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', name = 'tom', age = 10)
app.run(debug = True)
在第 1 行,从模块 flask 中导入函数 render_template,该函数将 jinja2 模板渲染为 html;在第 3 行,编写路径 / 的处理函数 index(),调用 render_template,对模板 templates/index.html 进行渲染。
render_template 包含有 2 个命名参数:name 和 age,模板引擎将模板 templates/index.html 中的变量进行替换。
2.3 编写模板文件 templates/index.html
<html>
<body>
<h2>My name is {{ name }}, I am {{ age }} years old</h2>
</body>
</html>
模板文件中的 {{ name }} 和 {{ age }} 被称为 jinja2 变量。render_template 包含有两个命名参数: name 和 age,{{ name }} 被替换为 name,{{ age }} 被替换为 age,最后渲染的 html 如下:
<html>
<body>
<h2>My name is tom, I am 10 years old</h2>
</body>
</html>
在浏览器中显示如下:
3. 分界符
jinja2 模板文件混合 html 语法与 jinja2 语法,使用分界符区分 html 语法与 jinja2 语法。有 5 种常见的分界符:
- {{ 变量 }},将变量放置在 {{ 和 }} 之间;
- {% 语句 %},将语句放置在 {% 和 %} 之间;
- # 语句,将语句放置在 # 之后;
- {# 注释 #},将注释放置在 {# 和 #} 之间;
- ## 注释,将注释放置在 # 之后。
以下模板文件包含了所有常见的分界符:
<!DOCTYPE html>
<html lang="en">
<body>
{{ variable }}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
<ul>
# for item in seq
<li>{{ item }}</li>
# endfor
</ul>
{# this is comment #}
## this is comment
</body>
</html>
4. 变量
1. 语法
jinja2 模板中,使用 {{ 和 }} 包围的标识符称为变量,模板渲染会将其替换为 Python 中的变量,语法如下:
{{ 变量 }}
2. jinja2 模板
定义演示变量功能的模板:
<html>
{{ string }}
<ul>
<li> {{ list[0] }}
<li> {{ list[0] }}
<li> {{ list[1] }}
</ul>
<ul>
<li> {{ dict['name'] }}
<li> {{ dict['age'] }}
</ul>
</html>
包含有 3 种类型的变量:字符串、列表、字典,它们会被替换为同名的 Python 变量。
3. jinja2 的模板输入
string = 'www.imooc.com'
list = ['www', 'imooc', 'com']
dict = {'name': 'zhangsan', 'age': 12}
4. 渲染后的 HTML
<html>
www.imooc.com
<ul>
<li> www
<li> www
<li> imooc
</ul>
<ul>
<li> zhangsan
<li> 12
</ul>
5. for 语句
1. 语法
jinja2 模板中,使用 {% 和 %} 包围的语法块称为语句,jinja2 支持类似于 Python 的 for 循环语句,语法如下:
{% for item in iterable %}
{% endfor %}
或者
# for item in iterable
# endfor
以上两者是等价的。
2. jinja2 模板
定义一个演示 for 循环语句功能的模板:
<h1>Members</h1>
<ul>
{% for user in users %}
<li>{{ user }}</li>
{% endfor %}
</ul>
在第 3 行,定义 for 循环语句,遍历列表 users;在第 4 行,在循环体中使用 {{ user }} 引用当前正在被遍历的元素。
3. jinja2 的模板输入
users = ['tom', 'jerry', 'mike']
4. 渲染后的 HTML
<h1>Members</h1>
<ul>
<li>tom</li>
<li>jerry</li>
<li>mike</li>
</ul>
6. if 语句
1. 语法
jinja2 模板中,使用 {% 和 %} 包围的语法块称为语句,jinja2 支持类似于 Python 的 if-else 判断语句,语法如下:
{% if cond %}
{% else %}
{% endif %}
jinja2 支持类似于 Python 的 if-elif 判断语句,语法如下:
{% if cond %}
{% elif cond %}
{% endif %}
2. jinja2 模板
定义一个演示 if 语句功能的模板:
<html>
{% if a %}
<p>a is True</p>
{% else %}
<p>a is False</p>
{% endif %}
{% if b %}
<p>b is True</p>
{% elif c %}
<p>b is False, and c is True</p>
{% endif %}
</html>
在模板中根据变量 a、b、c 的取值生成不同的内容。
3. jinja2 的模板输入
a = False
b = False
c = True
4. 渲染后的 html
<html>
<p>a is False</p>
<p>b is False, and c is True</p>
</html>
7. 测试
1. 语法
jinja2 提供的 tests 可以用来在语句里对变量或表达式进行测试,语法如下:
{% variable is test %}
完整的 test 请参考 https://jinja.palletsprojects.com/en/master/templates/#builtin-tests,部分的 test 如下:
test 名称 | 功能 |
---|---|
defined | 变量是否已经定义 |
boolean | 变量的类型是否是 boolean |
integer | 变量的类型是否是 integer |
float | 变量的类型是否是 float |
string | 变量是否是 string |
mapping | 变量的类型是否是字典 |
sequence | 变量的类型是否是序列 |
even | 变量是否是偶数 |
odd | 变量是否是奇数 |
lower | 变量是否是小写 |
upper | 变量是否是大写 |
2. jinja2 模板
定义一个演示 test 功能的模板:
<html>
{% if number is odd %}
<p> {{ number }} is odd
{% else %}
<p> {{ number }} is even
{% endif %}
{% if string is lower %}
<p> {{ string }} is lower
{% else %}
<p> {{ string }} is upper
{% endif %}
</html>
在第 2 行,number is odd 测试 number 是否为奇数;在第 8 行,string is lower 测试 string 是否为小写。
3. jinja2 的模板输入
number = 404
string = 'HELLO'
4. 渲染后的 html
<html>
<p> 404 is even
<p> HELLO is upper
</html>
8. 过滤器
1. 语法
jinja2 过滤器的是一个函数,语法如下:
{{ variable | filter }}
执行函数调用 filter(varialbe),把函数返回值作为这个代码块的值。
在词条 “jinja2 模板过滤器的使用” 中,详细讲解过滤器,本节仅仅给出一个简单例子。
2. jinja2 模板
<html>
{{ string | upper }}
</html>
3. jinja2 的模板输入
string = 'hello'
4. 渲染后的 html
<html>
HELLO
</html>
9. 小结
本节讲解 Flask 的默认模板语言 jinja2,通过具体的例子讲解了 jinja2 中的变量、if 语句、for 语句等概念,使用思维导图概括如下: