我所了解的模板引擎大部分都会提供类似Jinja2过滤器的功能,只不过叫法不同罢了。比如PHP Smarty中的Modifiers(变量调节器或修饰器),FreeMarker中的Build-ins(内建函数),连AngularJS这样的前端框架也提供了Filter过滤器。它们都是用来在变量被显示或使用前,对其作转换处理的。可以把它认为是一种转换函数,输入的参数就是其所修饰的变量,返回的就是变量转换后的值。
过滤器使用
回到我们第一篇的例子,我们在模板中对变量name作如下处理:
1
|
<
h1
>
Hello
{
{
name
|
upper
}
}
!
<
/
h1
>
|
你会看到name的输出都变成大写了。这就是过滤器,只需在待过滤的变量后面加上”|”符号,再加上过滤器名称,就可以对该变量作过滤转换。上面例子就是转换成全大写字母。过滤器可以连续使用:
1
|
<
h1
>
Hello
{
{
name
|
upper
|
truncate
(
3
,
True
)
}
}
!
<
/
h1
>
|
现在name变量不但被转换为大写,而且当它的长度大于3后,只显示前3个字符,后面默认用”…”显示。过滤器”truncate”有3个参数,第一个是字符截取长度;第二个决定是否保留截取后的子串,默认是False,也就是当字符大于3后,只显示”…”,截取部分也不出现;第三个是省略符号,默认是”…”。
其实从例子中我们可以猜到,过滤器本质上就是一个转换函数,它的第一个参数就是待过滤的变量,在模板中使用时可以省略去。如果它有第二个参数,模板中就必须传进去。
内置过滤器 Builtin Filters
Jinja2模板引擎提供了丰富的内置过滤器。这里介绍几个常用的。
字符串操作
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
|
{
# 当变量未定义时,显示默认字符串,可以缩写为d #}
<
p
>
{
{
name
|
default
(
'No name'
,
true
)
}
}
<
/
p
>
{
# 单词首字母大写 #}
<
p
>
{
{
'hello'
|
capitalize
}
}
<
/
p
>
{
# 单词全小写 #}
<
p
>
{
{
'XML'
|
lower
}
}
<
/
p
>
{
# 去除字符串前后的空白字符 #}
<
p
>
{
{
' hello '
|
trim
}
}
<
/
p
>
{
# 字符串反转,返回"olleh" #}
<
p
>
{
{
'hello'
|
reverse
}
}
<
/
p
>
{
# 格式化输出,返回"Number is 2" #}
<
p
>
{
{
'%s is %d'
|
format
(
"Number"
,
2
)
}
}
<
/
p
>
{
# 关闭HTML自动转义 #}
<
p
>
{
{
'<em>name</em>'
|
safe
}
}
<
/
p
>
{
%
autoescape
false
%
}
{
# HTML转义,即使autoescape关了也转义,可以缩写为e #}
<
p
>
{
{
'<em>name</em>'
|
escape
}
}
<
/
p
>
{
%
endautoescape
%
}
|
数值操作
1
2
3
4
5
6
7
8
|
{
# 四舍五入取整,返回13.0 #}
<
p
>
{
{
12.8888
|
round
}
}
<
/
p
>
{
# 向下截取到小数点后2位,返回12.88 #}
<
p
>
{
{
12.8888
|
round
(
2
,
'floor'
)
}
}
<
/
p
>
{
# 绝对值,返回12 #}
<
p
>
{
{
-
12
|
abs
}
}
<
/
p
>
|
列表操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
{
# 取第一个元素 #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
first
}
}
<
/
p
>
{
# 取最后一个元素 #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
last
}
}
<
/
p
>
{
# 返回列表长度,可以写为count #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
length
}
}
<
/
p
>
{
# 列表求和 #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
sum
}
}
<
/
p
>
{
# 列表排序,默认为升序 #}
<
p
>
{
{
[
3
,
2
,
1
,
5
,
4
]
|
sort
}
}
<
/
p
>
{
# 合并为字符串,返回"1 | 2 | 3 | 4 | 5" #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
join
(
' | '
)
}
}
<
/
p
>
{
# 列表中所有元素都全大写。这里可以用upper,lower,但capitalize无效 #}
<
p
>
{
{
[
'tom'
,
'bob'
,
'ada'
]
|
upper
}
}
<
/
p
>
|
字典列表操作
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
|
{
%
set
users
=
[
{
'name'
:
'Tom'
,
'gender'
:
'M'
,
'age'
:
20
}
,
{
'name'
:
'John'
,
'gender'
:
'M'
,
'age'
:
18
}
,
{
'name'
:
'Mary'
,
'gender'
:
'F'
,
'age'
:
24
}
,
{
'name'
:
'Bob'
,
'gender'
:
'M'
,
'age'
:
31
}
,
{
'name'
:
'Lisa'
,
'gender'
:
'F'
,
'age'
:
19
}
]
%
}
{
# 按指定字段排序,这里设reverse为true使其按降序排 #}
<
ul
>
{
%
for
user
in
users
|
sort
(
attribute
=
'age'
,
reverse
=
true
)
%
}
<
li
>
{
{
user
.
name
}
}
,
{
{
user
.
age
}
}
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
{
# 列表分组,每组是一个子列表,组名就是分组项的值 #}
<
ul
>
{
%
for
group
in
users
|
groupby
(
'gender'
)
%
}
<
li
>
{
{
group
.
grouper
}
}
<
ul
>
{
%
for
user
in
group
.
list
%
}
<
li
>
{
{
user
.
name
}
}
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
{
# 取字典中的某一项组成列表,再将其连接起来 #}
<
p
>
{
{
users
|
map
(
attribute
=
'name'
)
|
join
(
', '
)
}
}
<
/
p
>
|
更全的内置过滤器介绍可以从Jinja2的官方文档中找到。
Flask内置过滤器
Flask提供了一个内置过滤器”tojson”,它的作用是将变量输出为JSON字符串。这个在配合Javascript使用时非常有用。我们延用上节字典列表操作中定义的”users”变量
1
2
3
4
|
<script
type
=
"text/javascript"
>
var
users
=
{
{
users
|
tojson
|
safe
}
}
;
console
.
log
(
users
[
0
]
.
name
)
;
</script>
|
注意,这里要避免HTML自动转义,所以加上safe过滤器。
语句块过滤
Jinja2还可以对整块的语句使用过滤器。
1
2
3
|
{
%
filter
upper
%
}
This
is
a
Flask
Jinja2
introduction
.
{
%
endfilter
%
}
|
不过上述这种场景不经常用到。
自定义过滤器
内置的过滤器不满足需求怎么办?自己写呗。过滤器说白了就是一个函数嘛,我们马上就来写一个。回到Flask应用代码中:
1
2
|
def
double_step_filter
(
l
)
:
return
l
[
::
2
]
|
我们定义了一个”double_step_filter”函数,返回输入列表的偶数位元素(第0位,第2位,..)。怎么把它加到模板中当过滤器用呢?Flask应用对象提供了”add_template_filter”方法来帮我们实现。我们加入下面的代码:
1
|
app
.
add_template_filter
(
double_step_filter
,
'double_step'
)
|
函数的第一个参数是过滤器函数,第二个参数是过滤器名称。然后,我们就可以愉快地在模板中使用这个叫”double_step”的过滤器了:
1
2
|
{
# 返回[1,3,5] #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
double
_step
}
}
<
/
p
>
|
Flask还提供了添加过滤器的装饰器”template_filter”,使用起来更简单。下面的代码就添加了一个取子列表的过滤器。装饰器的参数定义了该过滤器的名称”sub”。
1
2
3
|
@
app
.
template_filter
(
'sub'
)
def
sub
(
l
,
start
,
end
)
:
return
l
[
start
:
end
]
|
我们在模板中可以这样使用它:
1
2
|
{
# 返回[2,3,4] #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
sub
(
1
,
4
)
}
}
<
/
p
>
|
Flask添加过滤器的方法实际上是封装了对Jinja2环境变量的操作。上述添加”sub”过滤器的方法,等同于下面的代码。
1
|
app
.
jinja_env
.
filters
[
'sub'
]
=
sub
|
我们在Flask应用中,不建议直接访问Jinja2的环境变量。如果离开Flask环境直接使用Jinja2的话,就可以通过”jinja2.Environment”来获取环境变量,并添加过滤器。
完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
from
flask
import
Flask
,
render_template
app
=
Flask
(
__name__
)
@
app
.
route
(
'/hello'
)
@
app
.
route
(
'/hello/<name>'
)
def
hello
(
name
=
None
)
:
return
render_template
(
'hello-3.html'
,
name
=
name
)
########## Add Filter ##########
def
double_step_filter
(
l
)
:
return
l
[
::
2
]
app
.
add_template_filter
(
double_step_filter
,
'double_step'
)
@
app
.
template_filter
(
'sub'
)
def
sub
(
l
,
start
,
end
)
:
return
l
[
start
:
end
]
#app.jinja_env.filters['sub'] = sub
if
__name__
==
'__main__'
:
app
.
run
(
host
=
'0.0.0.0'
,
debug
=
True
)
|
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
<
!
doctype
html
>
<
title
>
Hello
Sample
<
/
title
>
{
%
if
name
%
}
<
h1
>
Hello
{
{
name
|
upper
|
truncate
(
3
,
True
)
}
}
!
<
/
h1
>
{
%
else
%
}
<
h1
>
Hello
World
!
<
/
h1
>
{
%
endif
%
}
{
# 字符串操作 #}
{
# 当变量未定义时,显示默认字符串 #}
<
p
>
{
{
name
|
default
(
'No name'
,
true
)
}
}
<
/
p
>
{
# 单词首字母大写 #}
<
p
>
{
{
'hello'
|
capitalize
}
}
<
/
p
>
{
# 单词全小写 #}
<
p
>
{
{
'XML'
|
lower
}
}
<
/
p
>
{
# 去除字符串前后的空白字符 #}
<
p
>
{
{
' hello '
|
trim
}
}
<
/
p
>
{
# 字符串反转,返回"olleh" #}
<
p
>
{
{
'hello'
|
reverse
}
}
<
/
p
>
{
# 格式化输出,返回"Number is 2" #}
<
p
>
{
{
'%s is %d'
|
format
(
"Number"
,
2
)
}
}
<
/
p
>
{
# 关闭HTML自动转义 #}
<
p
>
{
{
'<em>name</em>'
|
safe
}
}
<
/
p
>
{
%
autoescape
false
%
}
{
# HTML转义,即使autoescape关了也转义 #}
<
p
>
{
{
'<em>name</em>'
|
escape
}
}
<
/
p
>
{
%
endautoescape
%
}
{
# 数值操作 #}
{
# 四舍五入取整,返回13.0 #}
<
p
>
{
{
12.8888
|
round
}
}
<
/
p
>
{
# 向下截取到小数点后2位,返回12.88 #}
<
p
>
{
{
12.8888
|
round
(
2
,
'floor'
)
}
}
<
/
p
>
{
# 绝对值,返回12 #}
<
p
>
{
{
-
12
|
abs
}
}
<
/
p
>
{
# 列表操作 #}
{
# 取第一个元素 #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
first
}
}
<
/
p
>
{
# 取最后一个元素 #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
last
}
}
<
/
p
>
{
# 返回列表长度 #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
length
}
}
<
/
p
>
{
# 列表求和 #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
sum
}
}
<
/
p
>
{
# 列表排序,默认为升序 #}
<
p
>
{
{
[
3
,
2
,
1
,
5
,
4
]
|
sort
}
}
<
/
p
>
{
# 合并为字符串,返回"1 | 2 | 3 | 4 | 5" #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
join
(
' | '
)
}
}
<
/
p
>
{
# 列表中所有元素都全大写。这里可以用upper,lower,但capitalize无效 #}
<
p
>
{
{
[
'tom'
,
'bob'
,
'ada'
]
|
upper
}
}
<
/
p
>
{
# 字典列表操作 #}
{
%
set
users
=
[
{
'name'
:
'Tom'
,
'gender'
:
'M'
,
'age'
:
20
}
,
{
'name'
:
'John'
,
'gender'
:
'M'
,
'age'
:
18
}
,
{
'name'
:
'Mary'
,
'gender'
:
'F'
,
'age'
:
24
}
,
{
'name'
:
'Bob'
,
'gender'
:
'M'
,
'age'
:
31
}
,
{
'name'
:
'Lisa'
,
'gender'
:
'F'
,
'age'
:
19
}
]
%
}
{
# 按指定字段排序,这里设reverse为true使其按降序排 #}
<
ul
>
{
%
for
user
in
users
|
sort
(
attribute
=
'age'
,
reverse
=
true
)
%
}
<
li
>
{
{
user
.
name
}
}
,
{
{
user
.
age
}
}
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
{
# 列表分组,每组是一个子列表,组名就是分组项的值 #}
<
ul
>
{
%
for
group
in
users
|
groupby
(
'gender'
)
%
}
<
li
>
{
{
group
.
grouper
}
}
<
ul
>
{
%
for
user
in
group
.
list
%
}
<
li
>
{
{
user
.
name
}
}
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
{
# 取字典中的某一项组成列表,再将其连接起来 #}
<
p
>
{
{
users
|
map
(
attribute
=
'name'
)
|
join
(
', '
)
}
}
<
/
p
>
{
# tojson #}
<script
type
=
"text/javascript"
>
var
users
=
{
{
users
|
tojson
|
safe
}
}
;
console
.
log
(
users
[
0
]
.
name
)
;
</script>
{
%
filter
upper
%
}
This
is
a
Flask
Jinja2
introduction
.
{
%
endfilter
%
}
{
# 自定义过滤器 #}
{
# 返回[1,3,5] #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
double
_step
}
}
<
/
p
>
{
# 返回[2,3,4] #}
<
p
>
{
{
[
1
,
2
,
3
,
4
,
5
]
|
sub
(
1
,
4
)
}
}
<
/
p
>
|
转载请注明:成长的对话 » Flask的Jinja2模板引擎 — 过滤器(3rd)