模版

Flask 利用 Jinja2 的模板引擎。当然你是自由地使用不同的模版引擎,但是你仍然必须安装 Jinja2 为了运行 Flask 本身。这个要求是必要的,为了丰富的扩展可用。所有的扩展是依赖于 Jinja2 的存在。

本节仅仅给出一个 Jinja2 如何融入 Flask 的快速介绍。如果想要关于模版引擎语法自身的信息,查看官方的 Jinja2 Template Documentation 获取更多的信息。

Jinja 配置

除非定制,Flask 中 Jinja2 配置如下:

  • 所有以 .html.htm.xml 以及 .xhtml 结尾的模版开启自动转义。

  • 一个模板可以用 {% autoescape %} 标签选择开关自动转义。

  • Flask 在 Jinja2 上下文中插入了几个全局函数和助手,另外还有一些目前默认的值。

标准上下文

下面全局变量默认在 Jinja2 模版中可用:

config

当前配置对象 (flask.config)

New in version 0.6.

Changed in version 0.10: 现在一直可用,即使是导入的模版。

request

当前请求对象 (flask.request)

session

当前会话对象 (flask.session)

g

实现全局变量的请求范围的对象 (flask.g)

url_for()

flask.url_for() 函数。

get_flashed_messages()

flask.get_flashed_messages() 函数。

Jinja 上下文行为

这些变量被添加到上下文变量,它们不是全局变量。不同在于,它们默认不会 在导入模板的上下文中出现。这样做,一方面是考虑到性能,另一方面是为了让事情显式透明。

对于你着意味着什么?如果你希望导入一个宏,你有两种可能来访问请求对象:

  1. 你显式地传入请求或请求对象的属性作为宏的参数。

  2. 使用 “with context” 导入宏。

在上下文中导入的方式如下:

{% from '_helpers.html' import my_macro with context %}

标准过滤器

这些过滤器在 Jinja2 中是可用的,也是 Jinja2 自带的过滤器:

tojson()

这个函数把给定的对象转换成 JSON 表示。如果你要动态生成 JavaScript 这里是一个非常有用的例子。

注意在 script 标签里面转义是不应该发生的,因此你打算在 script 标签里面使用它确保用 |safe 禁用转义:

<script type=text/javascript>
    doSomethingWith({{ user.username|tojson|safe }});
</script>

|tojson 过滤器会为你恰当地转义斜线。

控制自动转义

自动转义的概念是自动为你转义特殊字符。HTML (或者 XML,以及 XHTML)意义下的特殊字符是 &, >, <, " 以及 ' 。因为这些字符在文档中表示它们特定的含义, 如果你想在文本中使用它们,应该把它们替换成相应的“实体”。不这么做的话不仅仅会让用户很难 在文本中使用这么字符,而且会导致安全问题。(请参看 跨站脚本攻击(XSS) )

然而有时间你需要在模版中禁用自动转义。这种情况可能是你想要在页面中显式地插入 HTML, 比如内容来自一个 markdown 到 HTML 转换器的安全的 HTML 输出。

这有三种方式完成这个工作:

  • 在 Python 代码中,在传递到模板之前,用 Markup 对象封装 HTML 字符串。这是一般的推荐方法。

  • 在模版中,使用 |safe 过滤器显式地标记一个字符串为安全的 HTML。

  • 暂时地禁用自动转义系统。

你可以使用 {% 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=u'€'):
        return u'{0:.2f}{1}.format(amount, currency)
    return dict(format_price=format_price)

上面的上下文处理器使得 format_price 函数在所有模板中可用:

{{ format_price(0.33) }}

你也可以构建 format_price 为一个模板处理器(参看 注册过滤器), 但这展示了上下文处理器如何传递一个函数。