模板环境

模板上下文

通过 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 所示。

image 2025 01 21 13 19 47 940
Figure 1. 表4-3 Jinja2内置全局上下文变量

表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 所示。

image 2025 01 21 13 22 40 394
Figure 2. 表4-4 Jinja2内置全局函数

此外还有 3 个全局类,即 cycler、joiner、namespace,详细内容可参考 Jinja2 官方文档全局函数 https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-global-functions

除了 Jinja2 内置的全局函数外,Flask 也提供了两个全局函数,如表 4-5 所示。

image 2025 01 21 13 23 30 701
Figure 3. 表4-5 Flask提供的全局函数

url_for 函数可以用来构建 URL 和加载静态文件,构建 URL 与在 Python 脚本中的用法是一样的,示例代码如下。

{{ url_for("book_detail",book_id=1) }}
html

关于 url_for 函数如何加载静态文件,以及 get_flashed_message 函数的使用,后续内容会详细讲解。

自定义全局函数

如果要实现自定义的全局函数,可以通过 app.template_global 装饰器来实现,示例代码如下。

@app.template_global()
def greet(name):
    return "欢迎!%s" % name
python

以上自定义的全局函数可以在模板中直接使用,示例代码如下。

<div>{{ greet("张三") }}</div>
html

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 进行了解。