flask_template

jinja2 基本语法

如果你只是配合 flask 使用 jinja2,那么 Template Designer Documentation 的这部分文档基本就够了,另一部分的 API 文档是面向那些比如说使用 jinja2 作为一个模板程序什么的。好了,正文开始。

The default Jinja delimiters:

variable

{{ variable }}; 获得 attribute 可以使用 {{ variable.attr }} 或者 {{ variable['attr'] }}, 两者等同; 设置 variable: {% set name='lord63' %}

Block Assignments:

{% set navigation %}
<li><a href="/">Index</a>
<li><a href="/downloads">Downloads</a>
{% endset %}

if

{% if age < 18 %}
   <p>You're not allowed to come in.</p>
{% endif %}

{% if kenny.sick %}
    Kenny is sick.
{% elif kenny.dead %}
    You killed Kenny!  You bastard!!!
{% else %}
    Kenny looks okay --- so far
{% endif %}

for

{% for user in users %}
    <li>{{ user.username|e }}</li>
{% endfor %}

comment

{# a block or a line #} or ## one line

filters

Do something on the variable, seperated by |, can be chained. e.g. {{ items|join(', ') }}. List of Builtin Filters

tests

Test a variable against a common expression. e.g. {% if loop.index is divisibleby(3) %}. List of Builtin Tests

reuse your code

在我看来呢,inheritence 就像类,子模板集成父模板的,比如你定义一个基本的 layout.html,所有的页面都是继承扩展这个模板的, 是一个通用基础; macro 就像函数,你把重复要用的放到一个 macro 中,重复利用。它是可拔插的,有的页面要用,就 import 进来, 因为如果每个页面都是要用的,就应该放到 layout.html 的基本模板中了。那么 include 的呢,我个人感觉就是为了更好的组织模板。 就像你会把一个 1000 行的文件分开来放在不同的文件中,虽然效果都是一样,但是每个文件目的性更加明确了,层次更加清楚了。

macros

Macros are comparable with functions in regular programming languages.

my_macro.html

{% macro input(name, value='', type='text', size=20) -%}
<input type="{{ type }}" name="{{ name }}" value="{{
   value|e }}" size="{{ size }}">
{%- endmacro %}

index.html

{% from 'my_macro.html' import input %}
...
<p>{{ input('username') }}</p>
...

inheritence

base.html

{% block style }
    <link rel="stylesheet" href="http://blabla.css">
{% endblock %}
...
{% block content }{% endblock %}
...

index.hytml(render the contents of the parent block by calling super)

{% extends 'base.html' %}
{% block style %}
    {{ super() }}
    <link rel="stylesheet" href="http://foobar.css">
{% endblock %}
{% block content %}
    <p> Hello, world.</p>
{% endblock %}

include

index.html

...
<p>This is the index page.</p>
{% include 'footer.html' %}

footer.html

<p>Powered by Flask.</p>

jinja2 in flask

最基本的就是 render_template('name.html', **kargs). 在 flask 中 jinja2 的使用更应该重视的是对模板文件的组织和分割, 具体的用法比如说 filters,tests 的细节直接翻文档就可以了。

default context

Documentation - Standard Context

template filter, template test, template global

三者分别对应 jinja2 中的 filter,test,global functions。前者是 decorator 用法,后者是实际底层调用的。 这个就像是平时我们一般用的 route 的 decorator 来定义路由,你也可以使用 add_url_rule 来实现,因为 route 这个 decorator 实际上就是 add_url_rule 的 wrapper。还有一点要提一下,有时候你可能会在使用 decorator 用法时忘记了 (), 这时候你想一想,这三个都是有一个 name 参数来使用你自定义的名字,所以是应该有 (), 因为我们平时都是没有定义而默认使用函数的名字, 所以记得加上 ().

Blueprint 也有对应的方法,只不过名字前多了一个 app,比如说 template_filter(name=None) -> app_template_filter(name=None). 故不再说明,用法是一样的。

flask template context processor

首先稍微定义一下 template context,jinja2 的文档中稍微提到了一下:

The dict or keywords arguments passed to the template are the so-called “context” of the template.

关于 template context processor 的用法,举个例子来说:

@app.context_processor
def inject_user():
    return dict(user='lord63')

这样的话,在模板文件中就直接可以使用 {{ name }} 了,不用再手动传进去了。当然,你也完全可以传个函数, 效果有点像 template_global()

@app.context_processor
def inject_user():
    def say_hi(name):
        return "hello, {0}".format(name)
    return dict(say_hi=say_hi)

{# in your template #}
<p>say_hi('lord63')</p>

Documentation - Context Processors