模板¶
Flask 利用 Jinja2 作为其模板引擎。您显然可以自由使用不同的模板引擎,但您仍然必须安装 Jinja2 才能运行 Flask 本身。此要求对于启用丰富的扩展是必要的。扩展可以依赖于 Jinja2 的存在。
本节仅简要介绍 Jinja2 如何集成到 Flask 中。如果您想了解模板引擎语法的相关信息,请访问官方 Jinja2 模板文档 获取更多信息。
Jinja 设置¶
除非自定义,否则 Jinja2 由 Flask 配置如下
当使用
render_template()
时,对于所有以.html
,.htm
,.xml
,.xhtml
以及.svg
结尾的模板,自动转义功能是启用的。当使用
render_template_string()
时,对于所有字符串,自动转义功能是启用的。模板可以使用
{% autoescape %}
标签选择启用/禁用自动转义。除了默认存在的值之外,Flask 还在 Jinja2 上下文中插入了几个全局函数和助手函数。
标准上下文¶
以下全局变量在 Jinja2 模板中默认可用
- config
当前的配置对象 (
flask.Flask.config
)更新日志
在 0.10 版本中变更: 现在始终可用,即使在导入的模板中也是如此。
在 0.6 版本中添加。
- request
当前的请求对象 (
flask.request
)。如果模板在没有活动请求上下文的情况下渲染,则此变量不可用。
- session
当前的会话对象 (
flask.session
)。如果模板在没有活动请求上下文的情况下渲染,则此变量不可用。
- g
请求绑定的全局变量对象 (
flask.g
)。如果模板在没有活动请求上下文的情况下渲染,则此变量不可用。
- url_for()
flask.url_for()
函数。
- get_flashed_messages()
Jinja 上下文行为
这些变量被添加到变量的上下文中,它们不是全局变量。不同之处在于,默认情况下,这些变量不会显示在导入的模板的上下文中。这部分是出于性能考虑,部分是为了保持显式。
这对您意味着什么?如果您有一个想要导入的宏,并且需要访问 request 对象,您有两种可能性
您显式地将 request 作为参数传递给宏,或者传递您感兴趣的 request 对象的属性。
您“带上下文”导入宏。
带上下文导入看起来像这样
{% from '_helpers.html' import my_macro with context %}
控制自动转义¶
自动转义是为您自动转义特殊字符的概念。HTML(或 XML,以及 XHTML)意义上的特殊字符是 &
, >
, <
, "
以及 '
。因为这些字符在文档中本身就带有特定的含义,所以如果您想将它们用于文本,则必须将它们替换为所谓的“实体”。不这样做不仅会导致用户因无法在文本中使用这些字符而感到沮丧,而且还可能导致安全问题。(请参阅 跨站脚本攻击 (XSS))
但是,有时您需要在模板中禁用自动转义。如果您想将 HTML 显式注入到页面中,例如,如果它们来自生成安全 HTML 的系统(如 markdown 到 HTML 转换器),则可能会出现这种情况。
有三种方法可以实现这一点
在 Python 代码中,在将 HTML 字符串传递给模板之前,将其包装在
Markup
对象中。这通常是推荐的方法。在模板内部,使用
|safe
过滤器显式地将字符串标记为安全 HTML ({{ myvariable|safe }}
)暂时完全禁用自动转义系统。
要在模板中禁用自动转义系统,您可以使用 {% autoescape %}
代码块
{% autoescape false %}
<p>autoescaping is disabled here
<p>{{ will_not_be_escaped }}
{% endautoescape %}
无论何时执行此操作,请务必谨慎对待您在此代码块中使用的变量。
注册过滤器¶
如果您想在 Jinja2 中注册自己的过滤器,您有两种方法可以做到这一点。您可以手动将它们放入应用程序的 jinja_env
中,或者使用 template_filter()
装饰器。
以下两个示例的工作方式相同,并且都反转一个对象
@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]
def reverse_filter(s):
return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter
在装饰器的情况下,如果您想使用函数名称作为过滤器的名称,则参数是可选的。注册后,您可以在模板中使用该过滤器,方式与 Jinja2 的内置过滤器相同,例如,如果您的上下文中有一个名为 mylist
的 Python 列表
{% for x in mylist | reverse %}
{% endfor %}
上下文处理器¶
为了自动将新变量注入到模板的上下文中,Flask 中存在上下文处理器。上下文处理器在模板渲染之前运行,并且能够将新值注入到模板上下文中。上下文处理器是一个返回字典的函数。然后将此字典的键和值与应用程序中所有模板的模板上下文合并
@app.context_processor
def inject_user():
return dict(user=g.user)
上面的上下文处理器使模板中可以使用名为 user
的变量,其值为 g.user
。此示例不是很有趣,因为 g
无论如何都可以在模板中使用,但它给出了此工作原理的想法。
变量不仅限于值;上下文处理器还可以使函数可用于模板(因为 Python 允许传递函数)
@app.context_processor
def utility_processor():
def format_price(amount, currency="€"):
return f"{amount:.2f}{currency}"
return dict(format_price=format_price)
上面的上下文处理器使 format_price
函数可用于所有模板
{{ format_price(0.33) }}
您还可以将 format_price
构建为模板过滤器(请参阅 注册过滤器),但这演示了如何在上下文处理器中传递函数。
流式处理¶
将整个模板渲染为一个完整的字符串可能不是很有用,而是将其渲染为流,从而产生较小的增量字符串。这可以用于以块的形式流式传输 HTML 以加快初始页面加载速度,或者在渲染非常大的模板时节省内存。
Jinja2 模板引擎支持逐片渲染模板,返回字符串的迭代器。Flask 提供了 stream_template()
和 stream_template_string()
函数,使之更易于使用。
from flask import stream_template
@app.get("/timeline")
def timeline():
return stream_template("timeline.html")
如果请求处于活动状态,这些函数会自动应用 stream_with_context()
包装器,以便它在模板中仍然可用。