模板环境
模板上下文
通过 render_template 传入的变量,实际上是保存到了模板的上下文中,当然 Jinja2 也有一些内置的上下文变量,可以通过 app.context_processor 来添加全局上下文。所以简单地理解上下文就是模板中可以直接使用的变量。
自定义变量
变量除了通过 render_template 渲染外,还可以在模板中通过 set 语法来定义新变量。示例代码如下。
{% set name='admin' %}
html
使用 set 赋值语句创建的变量在其之后都是有效的。如果不想让一个变量污染全局环境,可以使用 with 语句来创建一个内部的作用域,将 set 语句放到其中,这样创建的变量就只能在 with 代码块中才有效,示例代码如下。
{% with %} {% set foo = 42 %} {{ foo }} {% endwith %}
html
也可以在 with 后面直接添加变量,如以上写法可以简写成以下形式。
{% with foo = 42 %} {{ foo }} {% endwith %}
html
以上两种写法是等价的,一旦超出 with 代码块,就不能再使用 foo 这个变量了。
Jinja2内置全局上下文变量
Jinja2 为了方便开发者,已经提前内置了一些常用的全局上下文变量,如表 4-3 所示。

表4-3 所示的上下文变量可以在所有模板中直接使用,不需要额外传参。
上下文处理器
Jinja2 虽然内置了一些上下文变量,但有时候我们需要传递自定义的变量。如很多网站的导航条右上角会显示当前登录的用户名,这就需要把 user 变量传递到几乎所有模板中,如果通过 render_template 传递,则会很麻烦。这时就可以通过上下文处理器装饰器 @app.context_processor 来实现,示例代码如下。
@app.context_processor
def context_user():
user = {"username": "admin", "level": 2}
return {"user": user}
python
在自定义的上下文处理器函数中,需要把变量放到字典中才能在模板中被使用。另外,上下文中的变量,除了 Jinja2 内置的全局上下文变量以外,其余上下文变量不能再被 import 导入的模板中使用,如果需要使用,则需要使用 with context 语法,详情请参见 4.4.1 节 “宏和import语句”。
全局函数
内置全局函数
为了增强 Jinja2 模板的逻辑功能,Jinja2 内置了一些全局函数,这些函数在所有模板中都可以使用,包括被导入的模板。内置的全局函数如表 4-4 所示。

此外还有 3 个全局类,即 cycler、joiner、namespace,详细内容可参考 Jinja2 官方文档全局函数 https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-global-functions 。
除了 Jinja2 内置的全局函数外,Flask 也提供了两个全局函数,如表 4-5 所示。

url_for 函数可以用来构建 URL 和加载静态文件,构建 URL 与在 Python 脚本中的用法是一样的,示例代码如下。
{{ url_for("book_detail",book_id=1) }}
html
关于 url_for 函数如何加载静态文件,以及 get_flashed_message 函数的使用,后续内容会详细讲解。
Flask模板环境
在 Flask 中使用 Jinja2,还可以使用 app.jinja_env 属性来配置模板。app.jinja_env 是 jinja2.Environment 类的对象,下面讲解 jinja2.Environment 对象常用的属性。
设置autoescape
Jinja2 默认是开启了全局转义的,如果要关闭全局转义,可以通过以下代码实现。
# 关闭全局转义
app.jinja_env.autoescape = False
python
添加过滤器
添加过滤器可以通过 app.jinja_env.filters 实现,代码如下。
def myadd(a, b):
return a + b
app.jinja_env.filters["myadd"] = myadd
python
添加全局对象
app.template_global() 装饰器只能添加全局函数,如果需要其他 Python 对象,则可以通过 app.jinja_env.globals 实现,可以为其添加任意类型的 Python 对象,代码如下。
app.jinja_env.globals["user"] = user
python
添加测试器
添加测试器可以通过 app.jinja_env.tests 实现,代码如下。
def is_admin(user):
if user.role == "admin":
return True
else:
return False
app.jinja_env.tests["is_admin"] = is_admin
python
关于 jinja2.Environment 的其他属性,读者可以自行阅读其官方文档 https://jinja.palletsprojects.com/en/3.0.x/api/?highlight=environment#jinja2.Environment 进行了解。