3.1 Jinja2 模板引擎¶
Jinja2 是一种面向Python的现代且易于设计的模板语言。在该部分介绍 Jinja2 的语法和语义结构。
3.1.1 变量¶
模板变量通过上下文字典定义并传递给模板。在模板中使用 {{ variable }}
结构表示一个变量,这是一种特殊的占位符,告诉模板引擎这个位置的值从渲染模板时使用的数据获取。
Jinja2
能识别所有类型的变量,如列表、字典和对象等。如果要访问变量中的属性,可以使用.
或[]
来访问。
{{ mydict['key'] }}
{{ mydict.key }}
{{ myobj.attr }}
{{mylist[2]}}
变量的值可以使用过滤器修改。过滤器添加在变量名之后,二者之间以竖线分隔,例如将变量的值变为首字母大写的形式:
{{ name|capitalize}}
Jinja2 提供的常用过滤器:
过滤器名 |
说明 |
---|---|
safe |
渲染时不转义 |
capitalize |
把值的首字母转换成大写,其他字母转换成小写 |
lower |
把值转换成小写形式 |
upper |
把值转换成大写形式 |
title |
把值中每个单词的首字母转换成大写 |
trim |
把值的首尾空格删掉 |
striptags |
渲染之前把值中所有的 HTML 标签删掉 |
3.1.2 注释¶
如果要把模板中的一部分内容注释掉,使用 {# ... #}
:
{# note: disabled template because we no longer use this
{% for user in users %}
...
{% endfor %}
#}
3.1.3 控制结构¶
Jinja2 提供了多种控制结构,可用来改变模板的渲染流程。
条件控制(if-elif-else)
{% if condition1 %}
...
{% elif condition2 %}
...
{% else %}
...
{% endif %}
for 循环
<ul>
{% for comment in comments%}
<li>{{ comment }}</li>
{% endfor %}
</ul>
可以结合 if
进行一些条件过滤:
{% for comment in comments if condition %}
...
{% endfor %}
宏
宏类似 Python 中的函数。
{% macro render_comment(comment) %}
<li>{{ comment }}</li>
{% endmacro %}
调用宏:
<ul>
{% comment in comments %}
{{ render_comment(comment) }}
{% endfor %}
</ul>
为了重复使用宏,可以把宏保存在单独的文件中,然后再需要使用的模板中导入:
{% import 'macros.html' as macros %}
<ul>
{% comment in comments %}
{{ macros.render_comment(comment) }}
{% endfor %}
</ul>
3.1.4 模板继承¶
模板继承是指将公用的一部分代码抽取出来放到一个基模板中,然后子模板继承这部分内容。模板继承包括基模板和子模板。基模板里包含了网站里基本元素的基本骨架,但里面有一些空的或不完善的块(block)需要用子模板来填充。
继承语法:
{% extends “模板名称” %}
Jinja2 使用 block
和 endblock
指定在基模板中定义内容区块。
示例:在templates目录中创建base.html、index.html文件。
base.html 模板的内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{% block head %}
<title>{% block title %}{% endblock %} - 我的网站</title>
{% endblock %}
</head>
<body>
{% block body %}
这是基模板(base.html)中的内容
{% endblock %}
</body>
</html>
index.html 模板的内容:
{% extends "base.html" %}
{% block title %}网站首页{% endblock %}
{% block body %}
{{ super() }}
<h4>这是网站首页(index.html)的内容!</h4>
{% endblock %}
应用主程序app.py:
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)
执行主程序 app.py 后打开 http://127.0.0.1:5000/ 可以看到网站内容:
默认情况下,如果子模块实现了父模板定义的 block,那么子模板 block
中的代码就会覆盖父模板中的代码。例如,上述示例中在子模板 index.html 中
{% block title %}
定义内容会覆盖基模板 base.html
中的相应位置。如果想在子模版中仍然保持父模版代码,需要用 super()
函数调用。此外,如果想要在一个 block 中调用其他 block中的代码,可以通过
{{ self.其他block名称() }}
实现。