模板¶
Flask 使用 Jinja2 作为默认的模板渲染引擎。你可以自由更换其他的模板渲染引擎,但是你必须安装 Jinja2 来运行 Flask 本身。这个要求对于实现丰富的扩展是必要的。因为有些扩展使用 Jinja2 来实现功能。
本节只简要介绍了 Jinja2 是如何集成到Flask中的。如果你想知道有关 Jinja2 的更多语法,请访问官方的 Jinja2 模板文档 来获取更多信息。
Jinja 设置¶
除非被自定义,Jinja2 被 Flask 配置为以下内容:
当使用
render_template()时,所有文件名以.html,.htm,.xml,.xhtml以及.svg结尾的模板被配置了自动转义。当使用
render_template_string()时,所有字符串会被自动转义。模板可以使用
{% autoescape %}以选择是否使用自动转义。除了默认值之外,Flask 还在 Jinja2 上下文中插入了一些全局函数和辅助函数。
标准上下文¶
默认情况下,以下全局变量在 Jinja2 模板中可用:
- config
当前配置对象(
flask.Flask.config)Changelog
在 0.10 版本发生变更: 即使是在导入的模板中,这些也始终可用。
Added in version 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)意义上的特殊字符是 &,>,<," 以及 '。因为这些字符在文档中本身就有特定的含义,如果你想在文本中使用它们,你就必须用所谓的“实体”来代替它们。不这样做不仅会让用户因为无法在文本中用这些字符而感到沮丧,还会导致安全问题。(请参阅 Cross-Site Scripting (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() 包装器,以确保在模板中仍然可以访问请求上下文。