通过render_template传入的变量,实际上是保存到了模板的上下文中,当然Jinja2也有一些内置的上下文变量,可以通过app.context_processor来添加全局上下文。所以简单地理解上下文就是模板中可以直接使用的变量。
变量除了通过render_template渲染外,还可以在模板中通过set语法来定义新变量。示例代码如下。
{% set name='admin' %}
使用set赋值语句创建的变量在其之后都是有效的。如果不想让一个变量污染全局环境,可以使用with语句来创建一个内部的作用域,将set语句放到其中,这样创建的变量就只能在with代码块中才有效,示例代码如下。
{% with %} {% set foo = 42 %} {{ foo }} {% endwith %}
也可以在with后面直接添加变量,如以上写法可以简写成以下形式。
{% with foo = 42 %} {{ foo }} {% endwith %}
以上两种写法是等价的,一旦超出with代码块,就不能再使用foo这个变量了。
Jinja2为了方便开发者,已经提前内置了一些常用的全局上下文变量,如表4-3所示。
表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}
在自定义的上下文处理器函数中,需要把变量放到字典中才能在模板中被使用。另外,上下文中的变量,除了Jinja2内置的全局上下文变量以外,其余上下文变量不能再被import导入的模板中使用,如果需要使用,则需要使用with context语法,详情请参见4.4.1节“宏和import语句”。
为了增强Jinja2模板的逻辑功能,Jinja2内置了一些全局函数,这些函数在所有模板中都可以使用,包括被导入的模板。内置的全局函数如表4-4所示。
表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所示。
表4-5 Flask提供的全局函数
url_for函数可以用来构建URL和加载静态文件,构建URL与在Python脚本中的用法是一样的,示例代码如下。
{{ url_for("book_detail",book_id=1) }}
关于url_for函数如何加载静态文件,以及get_flashed_message函数的使用,后续内容会详细讲解。
如果要实现自定义的全局函数,可以通过app.template_global装饰器来实现,示例代码如下。
@app.template_global() def greet(name): return "欢迎!%s"%name
以上自定义的全局函数可以在模板中直接使用,示例代码如下。
<div>{{ greet("张三") }}</div>
在Flask中使用Jinja2,还可以使用app.jinja_env属性来配置模板。app.jinja_env是jinja2.Environment类的对象,下面讲解jinja2.Environment对象常用的属性。
Jinja2默认是开启了全局转义的,如果要关闭全局转义,可以通过以下代码实现。
# 关闭全局转义 app.jinja_env.autoescape = False
添加过滤器可以通过app.jinja_env.filters实现,代码如下。
def myadd(a,b): return a + b app.jinja_env.filters["myadd"] = myadd
app.template_global()装饰器只能添加全局函数,如果需要其他Python对象,则可以通过app.jinja_env.globals实现,可以为其添加任意类型的Python对象,代码如下。
app.jinja_env.globals["user"] = user
添加测试器可以通过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
关于jinja2.Environment的其他属性,读者可以自行阅读其官方文档https://jinja.palletsprojects.com/en/3.0.x/api/?highlight=environment#jinja2.Environment进行了解。