Jinjia2模板是一种文本文件,可以其格式可以是HTML、XML、CSV等等,其后缀没有命名限制。模板内部包含一些变量、表达式和标签,当渲染模板时,变量将被替换为具体的值,表达式将被计算,标签将按照模板语法进行解析执行。
1. 变量
模板的变量以字典的方式传入到模板中,变量中包含可访问的属性值或元素,这些都是由应用程序提供的。
1 2 3 |
{{ foo.bar }} {{ foo['bar'] }} {{ foo.bar.name }} |
2. 过滤器
变量的值可以通过过滤器进一步修改,并且依次被多个过滤器修改。
1 2 3 |
{{ var_name | title }} {{ var_name | striptags | title }} {{ listx|join(', ') }} |
常用的内置过滤器列表如下:
过滤器原型 | 说明 |
---|---|
abs(number) | 返回变量的绝对值 |
attr(obj, name) | 返回变量的指定属性值,如:foo |
batch(value, linecount, fill_with=None) | 若变量为集合,则将按linecount数量组合元素后再输出 |
capitalize(s) | 将变量字符串的首字母修改为大写 |
center(value, width=80) | 将变量字符串居中排版 |
default(value, default_value=u’‘, boolean=False) | 当变量值不存在时,为其设置默认值 |
dictsort(value, case_sensitive=False, by=’key’, reverse=False) | 对变量字典进行排序 |
escape(s) | 将变量中的特殊字符替换为HTML安全的字符 |
filesizeformat(value, binary=False) | 将变量转换为易于阅读的文件大小字符串 |
first(seq) | 返回变量集合中的第一个元素 |
float(value, default=0.0) | 将变量转换为float类型,如果转换失败,返回0.0 |
forceescape(value) | 强制变量将其内部的特殊字符替换为HTML安全的字符 |
format(value, args, *kwargs) | 格式化,{{ "%s - %s"|format("Hello?", "Foo!") }} |
groupby(value, attribute) | 通过变量序列的一个属性字段分组 |
indent(s, width=4, first=False, blank=False, indentfirst=None) | 为变量字符串添加缩进 |
int(value, default=0, base=10) | 将变量转换为int类型 |
join(value, d=u’‘, attribute=None) | 将变量值进行连接 |
last(seq) | 返回变量序列中的最后一个元素 |
length(object) | 返回变量中元素的个数 |
list(value) | 将变量值转换为一个list |
lower(s) | 将变量字符串转换为小写格式 |
max(value, case_sensitive=False, attribute=None) | 返回变量序列中的最大值 |
min(value, case_sensitive=False, attribute=None) | 返回变量序列中的最小值 |
replace(s, old, new, count=None) | 替换变量中的指定字符串 |
safe(value) | 将变量字符串标记为HTML安全的字符,不再对其进行替换处理 |
sort(value, reverse=False, case_sensitive=False, attribute=None) | 对变量序列进行排序 |
sum(iterable, attribute=None, start=0) | 对变量序列进行求和 |
title(s) | 将变量字符串转换为标题格式 |
tojson(value, indent=None) | 将变量转换为json格式 |
trim(value) | 去除变量前后空白字符 |
truncate(s, length=255, killwords=False, end=’…’, leeway=None) | 将变量字符串裁剪为指定长度 |
unique(value, case_sensitive=False, attribute=None) | 去除变量序列中的重复项 |
upper(s) | 将变量字符串转换为大写 |
urlencode(value) | 将变量编码为url |
urlize(value, trim_url_limit=None, nofollow=False, target=None, rel=None) | 将变量转换为可点击的url链接 |
wordcount(s) | 计算变量中的字数 |
wordwrap(s, width=79, break_long_words=True, wrapstring=None) | 将变量字符串按指定宽度自动换行 |
3. 条件测试
条件测试用于测试变量或表达式是否满足某个条件,从而实现模板中按条件进行渲染。常用的条件测试有:
条件测试表达式 | 说明 |
---|---|
callable(object) | 测试对象是否可调用 |
defined(value) | 测试变量是否已定义 |
divisibleby(value, num) | 测试变量是否可以被num整除 |
eq(a, b) | 测试变量是否相等,同== |
escaped(value) | 测试变量中的特殊字符是否已替换为HTML安全的字符 |
even(value) | 测试变量是否为偶数 |
ge(a, b) | 测试a是否大于等于b,同>= |
gt(a, b) | 测试a是否大于b,同> |
in(value, seq) | 测试变量是否在序列seq中 |
iterable(value) | 测试变量是否为可迭代对象 |
le(a, b) | 测试a是否小于等于b,同<= |
lt(a, b) | 测试a是否小于b,同< |
lower(value) | 测试变量是否为小写字符串 |
mapping(value) | 测试变量是否为字典类型 |
ne(a, b) | 测试变量是否不想等,同!= |
none(value) | 测试变量是否为None |
number(value) | 测试变量是否为数值 |
odd(value) | 测试变量是否为奇数 |
sameas(value, other) | 测试变量是否与other指向同一个对象 |
sequence(value) | 测试变量是否为序列 |
string(value) | 测试变量是否为字符串 |
undefined(value) | 测试变量是否未定义 |
upper(value) | 测试变量是否为大写字符串 |
4. 注释
在模板中,可通过 {# ... #} 来添加批量注释。
1 2 3 4 5 |
{# note: commented-out template because we no longer use this {% for user in users %} ... {% endfor %} #} |
5. 空白控制
默认情况下:
- 单独的一行空行将被移除;
- 其它的空白(空格、tab、新行)将被保留不变。
通过配置trim_blocks选项,可以使模板标签后的第一个新行自动删除;通过配置lstrip_blocks 选项可以删除模板中每个block的首行前的空白。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<--! 模板示例 --> <div> {% if True %} yay {% endif %} </div> <--! trim_blocks和lstrip_blocks都设置为True时 --> <div> yay </div> <--! trim_blocks和lstrip_blocks都设置为False时 --> <div> yay </div> |
此外,在模板block标签的开始或结束处添加 +可以对该block启动lstrip_blocks行为,在模板block标签的开始或结束处添加 - 可以删除该block前后的空白。
1 2 3 4 5 6 7 8 |
<div> {%+ if something %}yay{% endif %} </div> {# 当seq=range(1,10)时,输出为:123456789 #} {% for item in seq -%} {{ item }} {%- endfor %} |
6. 字符转义
可通过字符串字面值的方式输出特殊字符串,也可以通过raw块输出特殊格式的字符串。
1 2 3 4 5 6 7 8 9 10 11 |
{% 通过字面量输出 %} {{ '{{' }} {% 通过raw块输出 %} {% raw %} <ul> {% for item in seq %} <li>{{ item }}</li> {% endfor %} </ul> {% endraw %} |
7. 模板继承
Jinjia2模板引擎最得力的部分就是模板继承,它允许你创建一个基础的模板框架,其中包含你网站中所有的常用元素,并将这些常用元素定义为block,这些block可以在子模板中重写或继承。
基础模板框架示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!DOCTYPE html> <html lang="en"> <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> </html> |
子模板示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{% extends "layout/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 to my awesome homepage. </p> {% endblock %} |
8. 流程控制结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<h1>Members</h1> <ul> {% for user in users %} <li>{{ user.username }}</li> {% endfor %} </ul> <dl> {% for key, value in my_dict.iteritems() %} <dt>{{ key|e }}</dt> <dd>{{ value|e }}</dd> {% endfor %} </dl> {% for user in users if not user.hidden %} <li>{{ user.username|e }}</li> {% endfor %} <ul> {% for user in users %} <li>{{ user.username|e }}</li> {% else %} <li><em>no users found</em></li> {% endfor %} </ul> |
1 2 3 4 5 6 7 |
{% if kenny.sick %} Kenny is sick. {% elif kenny.dead %} You killed Kenny! You bastard!!! {% else %} Kenny looks okay --- so far {% endif %} |
1 2 3 4 |
{% macro input(name, value='', type='text', size=20) -%} <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}"> {%- endmacro %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{% 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 %} |
1 2 3 4 5 6 7 |
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %} {% set key, value = call_something() %} {% set navigation %} <li><a href="/">Index</a> <li><a href="/downloads">Downloads</a> {% endset %} |
1 2 3 4 5 6 |
{% include 'header.html' %} Body {% include 'footer.html' %} {% include ['page_detailed.html', 'page.html'] %} {% include ['special_sidebar.html', 'sidebar.html'] ignore missing %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{% import 'forms.html' as forms %} <dl> <dt>Username</dt> <dd>{{ forms.input('username') }}</dd> <dt>Password</dt> <dd>{{ forms.input('password', type='password') }}</dd> </dl> <p>{{ forms.textarea('comment') }}</p> {% from 'forms.html' import input as input_field, textarea %} <dl> <dt>Username</dt> <dd>{{ input_field('username') }}</dd> <dt>Password</dt> <dd>{{ input_field('password', type='password') }}</dd> </dl> <p>{{ textarea('comment') }}</p> |