模板

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()

flask.get_flashed_messages() 函数。

Jinja 上下文行为

这些变量被添加到变量的上下文中,它们不是全局变量。不同之处在于,默认情况下这些变量不会显示在导入模板的上下文中。这部分是出于性能考虑,部分是为了保持明确性。

这对您意味着什么?如果您有一个要导入的宏,需要访问请求对象,则您有两种可能性

  1. 您可以将请求作为参数或您感兴趣的请求对象的属性明确传递给宏。

  2. 您可以“使用上下文”导入宏。

使用上下文导入如下所示

{% 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() 包装器,以便它在模板中保持可用。