特性

  • 沙箱中执行
  • 强大的 HTML 自动转义系统保护系统免受 XSS
  • 模板继承
  • 及时编译最优的 python 代码
  • 可选提前编译模板的时间
  • 易于调试。异常的行数直接指向模板中的对应行。
  • 可配置的语法

安装

MarkupSafe替代Jinja2中老的加速模块,模块尽量安装c的版本;
基本API使用,通过 Template 创建一个模板并渲染它;
如果你的模板不是从字符串加载,而是文件系统或别的数据源,无论如何这都不是推荐的方式;

>>> from jinja2 import Template
>>> template = Template('Hello {{ name }}!')
>>> template.render(name='John Doe')
u'Hello John Doe!'

通过创建一个 Template 的实例,你会得到一个新的模板对象,提供一 个名为 render() 的方法,该方法在有字典或关键字参数时调用 扩充模板。字典或关键字参数会被传递到模板,即模板“上下文”。
unicode编码

模板

边界符号

{% ... %} 语句
{{ ... }} 表达式
{# ... #} 注释
#  ... ## 注释

变量
使用.或[]访问变量的属性

{{ foo.bar }}
{{ foo['bar'] }}

过滤器
会移除 name 中的所有 HTML,并且改写为标题样式的大小写格式;
接受带圆括号的参数{{ list|join(', ') }}

{{ name|striptags|title }}

内置过滤器

abs(number)
attr(obj, name)								#获得属性foo|attr("bar")
batch(value, linecount, fill_with=None)	
capitalize(s)
#未定义,如果boolean为ture那么这个变量就是定义的value;
default(value, default_value=u'', boolean=False) 
divisibleby(value, num)	#可除尽
escaped(value)	#是否是空白符
escaped(value)	#是否是奇数
iterable(value)	#对象是否可迭代
mapping(value)	#是否是一个mapping,比如字典

测试
测试如果只有一个采纳数,可以省略括号

{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}

内置的测试清单

callable(object)	#是否callable,可以被callable的类具有__call__()方法
defined(value)
lower(value)		#是否小写
none(value)
mapping(value)
number(value)
odd(value)
sameas(value, other)

测试例子

{% if var1 is lower %}
    lower
{% endif %}

注释

{# ... #}

空白
默认不会修改空白,使用trim_blocks,模板标签后的第一个换行会被移除
快开始前放一个-前后的空白会被移除
开启行语句会移除行首空白

{% for item in seq -%}
    {{ item }}
{%- endfor %}

转义
{{作为输出

{{ '{{' }}

还用raw

{% raw %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endraw %}

行语句
如果应用启用了行语句,就可以把一个行标记为一个语句。例如如果行语句前缀配置为 # ,下面的两个例子是等价的:

<ul>
# for item in seq
    <li>{{ item }}</li>
# endfor
</ul>

<ul>
{% for item in seq %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

为了语句有更好的可读性,在块的开始(比如 for 、 if 、 elif 等等)以冒号结尾:
2.2之后可以设置行注释,比如设置为##就可以作为注释
模板继承
首先定义一个基本模板

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
</head>
<body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
        © Copyright 2008 by <a href="http://domain.invalid/">you</a>.
        {% endblock %}
    </div>
</body>

{% block %} 标签定义了四个字幕版可以填充的块
所有的 block 标签 告诉模板引擎子模板可以覆盖模板中的这些部分
子模板

{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
    {{ super() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
      Welcome on my awesome homepage.
    </p>
{% endblock %}

{% extend %} 标签是这里的关键。它告诉模板引擎这个模板“继承”另一个模板。

模板的文件名依赖于模板加载器。例如 FileSystemLoader 允许你用文件名访问其它模板。你可以使用斜线访问子目录中的模板:

{% extends "layout/default.html" %}

不能定义同名块

嵌套块和作用域
嵌套块可以胜任更复杂的布局。而默认的块不允许访问块外作用域中的变量:

{% for item in seq %}
    <li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}

模板对象

控制结构清单

For

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

因为模板中的变量保留它们的对象属性,可以迭代像 dict 的容器
因为字典是无序的,需要 dictsort 过滤器

<dl>
{% for key, value in my_dict.iteritems() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

for循环中可以访问如下的变量

变量					描述
loop.index			当前循环迭代的次数(从 1 开始)
loop.index0			当前循环迭代的次数(从 0 开始)
loop.revindex		到循环结束需要迭代的次数(从 1 开始)
loop.revindex0		到循环结束需要迭代的次数(从 0 开始)
loop.first			如果是第一次迭代,为 True 。
loop.last			如果是最后一次迭代,为 True 。
loop.length			序列中的项目数。
loop.cycle			在一串序列间期取值的辅助函数。见下面的解释。

loop.cycle辅助函数,伴随循环在一个字符串/变量列表中周期取值:

不能使用break/continue,需要的话使用过滤器

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

如果序列为空,或内容都被滤除,可以使用一个else

<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% else %}
    <li><em>no users found</em></li>
{% endfor %}
</ul>

也可以递归地使用循环。当你处理诸如站点地图之类的递归数据时很有用。要递归地 使用循环,你只需要在循环定义中加上 recursive 修饰,并在你想使用递归的地 方,对可迭代量调用 loop 变量。
站点地图例子

<ul class="sitemap">
{%- for item in sitemap recursive %}
    <li><a href="{{ item.href|e }}">{{ item.title }}</a>
    {%- if item.children -%}
        <ul class="submenu">{{ loop(item.children) }}</ul>
    {%- endif %}</li>
{%- endfor %}
</ul>

If
类似python的if,可以判断真假、是否空

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

多分支

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


类似函数

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

之后可以像函数调用

<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>

宏内部的变量

varargs
如果有多于宏接受的参数个数的位置参数被传入,它们会作为列表的值保存在 varargs 变量上。
kwargs
同 varargs ,但只针对关键字参数。所有未使用的关键字参数会存储在 这个特殊变量中。
caller
如果宏通过 call 标签调用,调用者会作为可调用的宏被存储在这个 变量中。
宏也可以暴露某些内部细节。



下面的宏对象属性是可用的:
name
宏的名称。 {{ input.name }} 会打印 input 。
arguments
一个宏接受的参数名的元组。
defaults
默认值的元组。
catch_kwargs
如果宏接受额外的关键字参数(也就是访问特殊的 kwargs 变量),为 true 。
catch_varargs
如果宏接受额外的位置参数(也就是访问特殊的 varargs 变量),为 true 。
caller
如果宏访问特殊的 caller 变量且由 call 标签调用,为 true 。
如果一个宏的名称以下划线开始,它不是导出的且不能被导入。

Call
一个宏传递给另一个宏,使用call模块

{% macro render_dialog(title, class='dialog') -%}
    <div class="{{ class }}">
        <h2>{{ title }}</h2>
        <div class="contents">
            {{ caller() }}
        </div>
    </div>
{%- endmacro %}

{% call render_dialog('Hello World') %}
    This is a simple dialog rendered by using a macro and
    a call block.
{% endcall %}

这里是一个带参数的调用块的例子:

{% macro dump_users(users) -%}
    <ul>
    {%- for user in users %}
        <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
    {%- endfor %}
    </ul>
{%- endmacro %}

{% call(user) dump_users(list_of_user) %}
    <dl>
        <dl>Realname</dl>
        <dd>{{ user.realname|e }}</dd>
        <dl>Description</dl>
        <dd>{{ user.description }}</dd>
    </dl>
{% endcall %}

Filters

{% filter upper %}
    This text becomes uppercase
{% endfilter %}

赋值
在代码块中,你也可以为变量赋值;
在顶层的(块、宏、循环之外)赋值是可导出的,即 可以从别的模板中导入;

{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}

继承
包含 include

{% include 'header.html' %}
    Body
{% include 'footer.html' %}

这里是一些有效的例 子:

{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}

表达式

字面量,字符串或数值
字符串:"Hello World" 数值/浮点:42 / 42.23 列表:[‘list’, ‘of’, ‘objects’]
元组:(‘tuple’, ‘of’, ‘values’)
字典:{‘dict’: ‘of’, ‘key’: ‘and’, ‘value’: ‘pairs’}:
布尔:true / false
none

算术

模板中很少用到,但是支持
+:{{ 1 + 1 }} -:{{ 3 - 2 }}
*
**:幂运算
/:返回值会是一个浮点数
//:返回整数
%:取余

比较

==
!=

=
<
<=

逻辑

对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式:

and
or
not
(expr)
表达式组。

is和in使用中缀表示法,其他使用前缀表示法,比如

foo is not bar
foo not in bar
not (foo and bar)

其它运算符

其它运算符
下面的运算符非常有用,但不适用于其它的两个分类:

in:包含检查{{ 1 in [1,2,3] }} is:测试检查
|:过滤器
~:字符串连接` {{ "Hello " ~ name ~ "!" }},name可以是一个变量
():调用
. / []:获取一个属性对象

If 表达式

{% extends layout_template if layout_template is defined else 'master.html' %}

一般的语法是 <do something> if <something is true> else <do something else> else 部分是可选的。如果没有显式地提供 else 块,会求值一个未定义对象: