模板¶
Flask 利用 Jinja2 作为其模板引擎。您当然可以自由地使用不同的模板引擎,但您仍然必须安装 Jinja2 才能运行 Flask 本身。此要求对于启用丰富的扩展是必要的。扩展可以依赖于 Jinja2 的存在。
本节仅对 Jinja2 如何集成到 Flask 中进行了非常快速的介绍。如果您想要有关模板引擎本身语法的信息,请转到官方Jinja2 模板文档了解更多信息。
Jinja 设置¶
除非自定义,否则 Flask 会按如下方式配置 Jinja2
当使用
render_template()
时,所有以.html
、.htm
、.xml
、.xhtml
以及.svg
结尾的模板都启用自动转义。当使用
render_template_string()
时,所有字符串都启用自动转义。模板可以通过
{% autoescape %}
标签选择加入/退出自动转义。除了默认情况下存在的值之外,Flask 还将一些全局函数和帮助程序插入到 Jinja2 上下文中。
标准上下文¶
以下全局变量默认情况下可在 Jinja2 模板中使用
- config
当前配置对象(
flask.Flask.config
)Changelog
在 0.10 版中更改:现在始终可用,即使在导入的模板中也是如此。
0.6 版新增。
- request
当前请求对象(
flask.request
)。如果在没有活动请求上下文的情况下呈现模板,则此变量不可用。
- session
当前会话对象(
flask.session
)。如果在没有活动请求上下文的情况下呈现模板,则此变量不可用。
- g
全局变量的请求绑定对象 (
flask.g
)。如果在没有活动请求上下文的情况下渲染模板,则此变量不可用。
- url_for()
flask.url_for()
函数。
- get_flashed_messages()
Jinja 上下文行为
这些变量被添加到变量的上下文中,它们不是全局变量。不同之处在于,默认情况下这些变量不会显示在导入模板的上下文中。这部分是出于性能考虑,部分是为了保持明确性。
这对您意味着什么?如果您有一个要导入的宏,需要访问请求对象,则您有两种可能性
您可以将请求作为参数或您感兴趣的请求对象的属性明确传递给宏。
您可以“使用上下文”导入宏。
使用上下文导入如下所示
{% 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()
包装器,以便它在模板中保持可用。