在动态Web程序中,视图函数返回的HTML数据往往需要根据相应的变量(比如查询参数)动态生成。当HTML代码保存到单独的文件中时,我们没法再使用字符串格式化或拼接字符串的方式来在HTML代码中插入变量,这时我们需要使用模板引擎。借助模板引擎,我们可以在HTML文件中使用特殊语法来标记出变量,这类包含固定内容和动态部分的可重用文件称为模板。
模板引擎的作用就是读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,输出最终的HTML页面,这个过程被称为渲染。Flask默认使用的模板引擎是Jinja2,它是一个功能齐全的Python模板引擎,除了设置变量外,还允许我们在模板中添加if判断,执行for迭代,调用函数等,以各种方式控制模板的输出。对于Jinja2来说,模板可以是任何格式的纯文本文件,比如HTML、XML、 CSV、LaTeX等。
创建一些虚拟数据用于测试:
user = {
'username': 'Grey Li',
'bio': 'A boy who loves movies and music.',
}
movies = [
{'name': 'My Neighbor Totoro', 'year': '1988'},
{'name': 'Three Colours trilogy', 'year': '1993'},
{'name': 'Forrest Gump', 'year': '1994'},
{'name': 'Perfect Blue', 'year': '1997'},
{'name': 'The Matrix', 'year': '1999'},
{'name': 'Memento', 'year': '2000'},
{'name': 'The Bucket list', 'year': '2007'},
{'name': 'Black Swan', 'year': '2010'},
{'name': 'Gone Girl', 'year': '2014'},
{'name': 'CoCo', 'year': '2017'},
]
template/watchlist.html
<!DOCTYPE html>
{% set navigation = [('/', 'Home'), ('/about', 'About')] %}
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ user.username }}'s Watchlist</title>
</head>
<body>
<a href="{{ url_for('index') }}">← Return</a>
<h2>{{ user.username }}</h2>
{% if user.bio %}
<i>{{ user.bio }}</i>
{% else %}
<i>This user has not provided a bio.</i>
{% endif %}
<h5>{{ user.username }}'s Watchlist ({{ movies|length }}):</h5>
<ul>
{% for movie in movies %}
<li>{{ movie.name }} - {{ movie.year }}</li>
{% endfor %}
</ul>
</body>
</html>
模板语法
利用Jinja2这样的模板引擎,我们可以将一部分的程序逻辑放到模板中去。简单地说,我们可以在模板中使用Python语句和表达式来操作数据的输出。但需要注意的是,Jinja2并不支持所有Python语法。而且出于效率和代码组织等方面的考虑,我们应该适度使用模板,仅把和输出控制有关的逻辑放到模板中。
Jinja2允许你在模板中使用大部分Python对象,比如字符串、列表、字典、元组、整型、浮点型、布尔值。它支持基本的运算符号(+ - * /等)、比较符号(如\=\=、!\=等)、逻辑符号(and、or、not和括号)以及in
is、None和布尔值(True、False)
Jinja2提供了多种控制结构来控制模板的输出,其中for和if是最常用 的两种。在Jinja2里,语句使用{%...%}标识,尤其需要注意的是,在语 句结束的地方,我们必须添加结束标签:
和其他语句一样,你需要在for循环的结尾使用endfor标签声明for语 句的结束。在for循环内,Jinja2提供了多个特殊变量,常用的循环变量 如表3-1所示。
loop.index 当前迭代数(从1开始计数)
loop.index0 当前迭代数(从0开始计数)
loop.revindex 当前反向迭代数(从1开始计数)
loop.revindex0 当前反向迭代数(从0开始计数)
loop.first 如果是第一个元素,则为True
loop.last 如果是最后一个元素,则为True
loop.previtem 上一个迭代的条目
loop.nextitem 下一个迭代的条目
loop.length 序列包含的元素数量
0 Comments latest
No comments.