介绍
大概介绍一下,主要介绍模板(模板仅仅是文本文件。它可以生成任何基于文本的格式(HTML、XML、CSV、LaTex 等等)。它并没有特定的扩展名,.html
或.xml
都是可以的。)模板包含变量或表达式 ,这两者在模板求值的时候会被替换为值。模板中 还有标签,控制模板的逻辑。模板语法的大量灵感来自于 Django和Python。
Jinja2是一个现代的,设计者友好的,仿照Django模板的Python模板语言。它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全.特征如下:
- 沙箱中执行
- 强大的HTML自动转义系统保护系统免受XSS
- 模板继承
- 及时编译最优的python代码
- 易于调试。异常的行数直接指向模板中的对应行
- 可配置的语法
—选自 http://docs.jinkan.org
注意
- Jinja2需要至少Python2.4版本来运行
- 使用的时候推荐
# -*- coding: utf-8 -*-
。
Jinja2内部使用Unicode ,这意味着你需要向渲染函数传递 Unicode 对象或只包含 ASCII 字符的字符串。此外,换行符按照默认 UNIX 风格规定行序列结束( \n )
- 从Jinja2 2.4版本开始支持自动转义(autoescape参数)。自动转义扩展允许你在模板内开关自动转义特性。如果环境的 autoescape 设定为 False ,它可以被激活。如果是 True 可以被关闭。这个设定的覆盖是有作用域的。
—选自 W3Cschool Jinja2文档
模板(变量 及 过滤器)
变量
变量可以有两种形式,但实际不太一样,另外注意{{ }}
不是变量的一部分,而是打印语句的一部分
{{ foo.bar }}
使用foo.bar实际在python层面做了以下事情
- 检查foo上是否有一个名为bar的属性
- 若没有,检查foo中是否有一个bar的项
- 若没有,返回一个未定义的对象
{{ foo['bar'] }}
-使用foo[‘bar’]如下
-检查foo中是否有一个名为bar的项
-若没有,检查foo中是否有一个名为bar的属性
-若没有,返回一个未定义的对象
变量赋值
1
2
|
{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
|
过滤器
变量可以通过过滤器修改。过滤器与变量用管道符|
分割,并且也可以用圆括号传递可选参数。多个过滤器可以链式调用
常见的内置过滤器如下:
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
abs(number) #取绝对值
attr(obj, name) #获得对象属性
batch(value, linecount, fill_with=None) #批处理项目的过滤器,类似切片
capitalize(s) #将第一个字母大写其余小写
center(value, width=80) #将值的宽度增加到指定值
default(value, default_value=u'', boolean=False) #如果值未定义就设置为默认值,如果要对布尔值使用boolean参数需要为True
dictsort(value, case_sensitive=False, by='key') #对字典进行排序
escape(s) #将字符串中的字符&、'、和'转换为安全的序列。如果您需要在HTML中显示可能包含此类字符的文本,请使用此选项。将返回值标记为标记字符串。
filesizeformat(value, binary=False) #将文件大小格式转化为便于阅读的格式,如MB,G
first(seq) #返回序列中的第一个,字符串列表都可以,字符串如果包括,会以,分割,列表直接拿第一项
float(value, default=0.0) #将输入转换成浮点数,转换失败就返回默认值
forceescape(value) #强制HTML转义。这可能会使转义变量翻倍
format(value, args, kwargs*) #给对象应用python字符串格式,如value="%s - %s"
groupby(value, attribute) #使用公共属性将对象序列分组
indent(s, width=4, indentfirst=False) #返回传递字符串的副本,每行缩进4个空格。第一行没有缩进。如果您想更改空格数或缩进第一行,可以向筛选器传递其他参数
int(value, default=0) #将输入转换成整数,转换失败就返回默认值
join(value, d=u'', attribute=None) #将列表拼接,也可以连接对象的某些属性
last(seq) #返回序列中的最后一个
length(object) #返回序列或映射的项数,最简单可以看str的长度,已经列表的元素数
list(value) #将值转化为列表
lower(s) #将值转化为小写
map() #映射属性,对对象序列应用过滤器或查找属性,如{{ titles|map('lower')|join(', ') }}
pprint(value, verbose=False) #方便调试,美观的打印
random(seq) #从序列中返回随机项目
reject() #通过将测试应用于对象或属性,并在测试成功后拒绝这些对象来过滤对象序列。
rejectattr() #通过将测试应用于对象或属性,并在测试成功后拒绝这些对象来过滤对象序列。
replace(s, old, new, count=None) #查找替换
reverse(value) #反转对象
round(value, precision=0, method='common') #将数字舍入到给定的精度。第一个参数指定精度(默认值为0),第二个参数指定舍入方法
safe(value) #将该值标记为安全,这意味着在启用自动转义的环境中,该变量不会被转义。
select() #通过将测试应用于对象或属性,并仅选择测试成功的对象,过滤对象序列。
selectattr() #通过将测试应用于对象或属性,并仅选择测试成功的对象,过滤对象序列。
slice(value, slices, fill_with=None) #分割迭代器并返回包含这些项目的列表。当创建包含三个表示列的ul标记的div时很有用
sort(value, reverse=False, case_sensitive=False, attribute=None) #排序
string(object) #创建字符串unicode
striptags(value) #去掉SGML/XML标签,用一个空格替换相邻的空格。
sum(iterable, attribute=None, start=0) #返回数字的和,如{{ items|sum(attribute='price') }}
title(s) #返回该值的标题大小写版本。即单词将以大写字母开头,所有剩余字符都是小写的
trim(value) #去掉开头和结尾的空格
truncate(s, length=255, killwords=False, end='...') #截断字符串指定长度
upper(s) #将值转为大写
urlencode(value) #用于网址的转义字符串(使用UTF-8编码)。既接受字典和常规字符串也接受成对的iterables。
urlize(value, trim_url_limit=None, nofollow=False) #将纯文本网址转换为可点击
wordcount(s) #返回字符串中的单词数
wordwrap(s, width=79, break_long_words=True, wrapstring=None) #返回传递给筛选器的字符串的副本,该字符串在指定个字符后换行
xmlattr(d, autospace=True) #基于字典中的项目创建一个SGML/XML属性字符串。所有既不是无也不是未定义的值都会自动转义
|
过滤器小栗子
1
2
3
|
{% filter upper %}
This text becomes uppercase
{% endfilter %}
|
基础语法
测试
测试可以对普通表达式进行测试变量,测试也可以接受参数。如果测试只接受一个参数,你可以省去括号来分组它们
1
|
{% if loop.index is divisibleby(3) %}
|
内置测试清单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
callable(object) #对象是否可调用
defined(value) #是否定义
divisibleby(value, num) #能否被整除
escaped(value) #是否转义
even(value) #如果是偶数为true
iterable(value) #是否有可迭代对象
lower(value) #小写返回true
mapping(value) #字典返回true
none(value) #空返回true
number(value) #数字返回true
odd(value) #变量为奇数返回true
sameas(value, other) #是否指向相同的内存地址
sequence(value) #列表返回true
string(value) #字符串返回true
undefined(value) #是否未定义
upper(value) #大写返回true
|
注释&空白控制&转义
注释: 在模板内进行注释使用{# 要注释的内容 #}
,如
1
2
3
4
5
|
{# note: disabled template example
{% for user in users %}
...
{% endfor %}
#}
|
空白控制 :默认情况下,模板引擎不会对空白进行修改,如果配置了Jinja的trim_blocks
则模板标签后的第一个换行符会被移除,另外,可以通过在块的开始或结束放置一个减号-
注意:标签和减号之间不能有空格,可以移除块前或块后的空白.
1
2
3
4
5
6
|
#demo1: 生成不换行的所有元素
{% for item in seq -%}
{{ item }}
{%- endfor %}
#demo2
{%- if foo -%}...{% endif %}
|
**转义:**较短的转义可以使用变量表达式,较长的内容或段落可以通过raw
1
2
3
4
5
6
7
8
|
#demo1
{{ '{' }}
#demo2
{% raw %}
{% for i in [1,2,3] %}
<li>{{ i }}</li>
{% endfor %}
{% endraw %}
|
扩展:
当从模板生成 HTML 时,始终有这样的风险:变量包含影响已生成 HTML 的字符。有两种 解决方法:手动转义每个字符或默认自动转义所有的东西。
- 使用手动转义: 转义通过用管道传递到过滤器 |e 来实现: {{ user.username|e }} 。
- 使用自动转义: 当启用了自动转移,默认会转移一切,除非值被显式地标记为安全的
行语句
如果配置启用行语句,就可以把一个行标记为一个句子。例如如果行语句前缀配置为'#',那么#for item in [1,2,3]
和{% for item in [1,2,3] %}
就是等效的。
- 行语句可以出现在一行的任意位置,只要它的前面没有文本,提升可读性
- 如果有未闭合的圆括号、花括号或方括号,那么行语句可以跨越多行
- 从Jinja2.2版本开始,行注释可以使用了,例如如果配置
##
为行注释前缀,行中所有##
后面的内容都会被忽略(不包括换行符)
模板继承&包含
模板继承可以说是Jinja最强大的部分了,模板继承允许定义一个基础模板,然后定义子模板可以覆盖的块。如下例子
基础模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!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://gourds.site/">Gourds</a>.
{% endblock %}
</div>
</body>
|
子模板s1
{% extends%}
标签确定继承的模板,也可以访问多级目录下的模板{% extends "path_to/my_template.html" %}
。使用super()
可以调用super来渲染父级块的内容,会返回父级块的结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index Test </h1>
<p class="important">
Gourds test page s1.
</p>
{% endblock %}
|
推荐使用命名块结束标签提升可读性(endblock
后面写的要与block
后面的对应),如
1
2
3
4
5
|
{% block my_data %}
{% block you_data %}
...
{% endblock you_data %}
{% endblock my_data%}
|
嵌套块和作用域
默认的块不允许访问块外作用域中的变量,嵌套块可以.从Jinja2.2开始,只需在块声明中添加scoped
装饰,就可以显示的指定在块中可用的变量,当覆盖一个块时不需要scoped
1
2
3
|
{% for item in seq %}
<li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}
|
包含
Include语句用于包含一个模板,并在当前命名空间返回文件的渲染结果,包含的模板默认可以访问活动的上下文中的变量
1
2
3
|
{% include 'header.html' %}
Body
{% include 'footer.html' %}
|
控制结构
for语句
遍历列表中的每一元素,支持大部分python语法。注意不能在循环中使用break
或continue
.但可以通过过滤来跳过项目,如{% for user in users if not user.hidden %}
1
2
3
4
5
6
7
8
|
{% for k,v in local_data.items() %}
<tr>
<td>{{ v['Name'] }}</td>
<td>{{ v.Age }}</td>
<td>{{ v.Site }}</td>
</tr>
{% endfor %}
|
如果因序列是空或者过滤移除了序列中的所有项目而没有执行循环,你可以使用 else 渲染一个用于替换的块
1
2
3
4
5
6
7
|
<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
8
|
<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>
|
在for循环中可用的特殊变量
变量名 |
描述 |
loop.index |
当前迭代次数从1开始 |
loop.index0 |
当前迭代次数从0开始 |
loop.revindex |
到循环结束需要迭代的次数从1开始 |
loop.revindex0 |
到循环结束需要迭代的次数从0开始 |
loop.first |
如果是第一次迭代为True |
loop.last |
如果是最后一次迭代为True |
loop.length |
列表中的项目数 |
loop.cycle |
在表表间期取值的辅助函数 |
if语句
跟python中的if差不多,可以使用if、elif、else
,可以测试变量或其他表达式,在jinja中也可以叫做内联表达式或者循环过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{% 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 %}
|
关于宏
类似其他语言,宏用来将重复行为分装成可重用的函数.如果宏在不同模板定义需要先import
,如果一个宏的名称以下划线开始,则它不能导出且不能被导入
宏内部,可以访问的特殊的变量
varargs
:多于宏接受的参数个数的位置参数被传入,它们会作为列表的值保存在 varargs变量上
kwargs
:同varargs,但只针对关键字参数。所有未使用的关键字参数会存储在这个特殊变量中
caller
:如果宏通过call标签调用,调用者会作为可调用的宏被存储在这个变量中
name
:宏的名称
arguments
:一个宏接受的参数名的元组
defaults
:默认值的元组
catch_kwargs
:如果宏接受额外的关键字参数,为true
catch_varargs
:如果宏接受额外的位置参数,为true
caller
:如果宏访问特殊的caller变量且由call标签调用,为true
如下例子,定义宏
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
|
<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>
|
带参数调用块的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
{% 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 %}
|
表达式
比较:
==
/!=
- and/or/not
is
/in
/|
(应用过滤器)/()
调用一个可调用对象/
算数运算:
典型示例
导入模板并使用模板中的宏,如下是被导入的forms.html
1
2
3
4
5
6
7
8
|
{% macro input(name, value='', type='text') -%}
<input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
{%- endmacro %}
{%- macro textarea(name, value='', rows=10, cols=40) -%}
<textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols
}}">{{ value|e }}</textarea>
{%- endmacro %}
|
可以这样使用
1
2
3
4
5
6
7
8
|
{% 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>
|
还可以导入到命名空间中
1
2
3
4
5
6
7
8
|
{% 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>
|
基本是W3Cschool
的学习笔记,大部分是复制粘贴的,相当于读写一遍,侵删,以上