Jinja2模板引擎的另一个辅助函数功能,即全局函数Global Functions。如果说过滤器是一个变量转换函数,测试器是一个返回布尔值的函数,那全局函数就可以是任意函数。可以在任一场景使用,没有输入和输出值的限制。本篇我们就来阐述下这个全局函数。
全局函数使用
还是取出第一篇开篇的代码,我们在模板中加入下面的代码:
1
2
3
4
5
|
<
ul
>
{
%
for
num
in
range
(
10
,
20
,
2
)
%
}
<
li
>
Number
is
"{{ num }}"
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
|
页面上会显示”10,12,14,16,18″5个列表项。全局函数”range()”的作用同Python里的一样,返回指定范围内的数值序列。三个参数分别是开始值,结束值(不包含),间隔。如果只传两个参数,那间隔默认为1;如果只传1个参数,那开始值默认为0。
由此可见,全局函数如同其名字一样,就是全局范围内可以被使用的函数。其同第二篇介绍的上下文环境中定义的函数不同,没有请求生命周期的限制。
内置全局函数
演示几个常用的内置全局函数。
- dict()函数,方便生成字典型变量
1
2
3
4
|
{
%
set
user
=
dict
(
name
=
'Mike'
,
age
=
15
)
%
}
<
p
>
{
{
user
|
tojson
|
safe
}
}
<
/
p
>
{
# 显示 '{"age": 15, "name": "Mike"}' #}
|
- joiner()函数,神奇的辅助函数。它可以初始化为一个分隔符,然后第一次调用时返回空字符串,以后再调用则返回分隔符。对分隔循环中的内容很有帮助
1
2
3
4
5
6
|
{
%
set
sep
=
joiner
(
"|"
)
%
}
{
%
for
val
in
range
(
5
)
%
}
{
{
sep
(
)
}
}
<
span
>
{
{
val
}
}
<
/
span
>
{
%
endfor
%
}
{
# 显示 "0 | 1 | 2 | 3 | 4" #}
|
- cycler()函数,作用同第一篇介绍的循环内置变量”loop.cycle”类似,在给定的序列中轮循
1
2
3
4
5
6
7
|
{
%
set
cycle
=
cycler
(
'odd'
,
'even'
)
%
}
<
ul
>
{
%
for
num
in
range
(
10
,
20
,
2
)
%
}
<
li
class
=
"{{ cycle.next() }}"
>
Number
is
"{{ num }}"
,
next
line
is
"{{ cycle.current }}"
line
.
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
|
基于上一节的例子,加上”cycler()”函数的使用,你会发现列表项<li>的”class”在”odd”和”even”两个值间轮循。加入第一篇中的CSS style,就可以看到斑马线了。
“cycler()”函数返回的对象可以做如下操作
- next(),返回当前值,并往下一个值轮循
- reset(),重置为第一个值
- current,当前轮循到的值
更全的内置全局函数介绍可以从Jinja2的官方文档中找到。
自定义全局函数
我们当然也可以写自己的全局函数,方法同之前介绍的过滤器啦,测试器啦都很类似。就是将Flask应用代码中定义的函数,通过”add_template_global”将其传入模板即可:
1
2
3
4
5
6
7
8
9
|
import
re
def
accept_pattern
(
pattern_str
)
:
pattern
=
re
.
compile
(
pattern_str
,
re
.
S
)
def
search
(
content
)
:
return
pattern
.
findall
(
content
)
return
dict
(
search
=
search
,
current_pattern
=
pattern_str
)
app
.
add_template_global
(
accept_pattern
,
'accept_pattern'
)
|
上例中的accept_pattern函数会先预编译一个正则,然后返回的字典中包含一个查询函数”search”,之后调用”search”函数就可以用编译好的正则来搜索内容了。”app.add_template_global”方法的第一个参数是自定义的全局函数,第二个是全局函数名称。现在,让我们在模板中使用”accept_pattern”全局函数:
1
2
3
4
5
6
7
8
9
|
{
%
with
pattern
=
accept_pattern
(
"<li>(.*?)</li>"
)
%
}
{
%
set
founds
=
pattern
.
search
(
"<li>Tom</li><li>Bob</li>"
)
%
}
<
ul
>
{
%
for
item
in
founds
%
}
<
li
>
Found
:
{
{
item
}
}
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
<
p
>
Current
Pattern
:
{
{
pattern
.
current
_pattern
}
}
<
/
p
>
{
%
endwith
%
}
|
“Tom”和”Bob”被抽取出来了,很牛掰的样子。你还可以根据需要在”accept_pattern”的返回字典里定义更多的方法。
Flask同样提供了添加全局函数的装饰器”template_global”,以方便全局函数的添加。我们来用它将第二篇中取系统当前时间的函数”current_time”定义为全局函数。
1
2
3
4
|
import
time
@
app
.
template_global
(
'end_with'
)
def
current_time
(
timeFormat
=
"%b %d, %Y - %H:%M:%S"
)
:
return
time
.
strftime
(
timeFormat
)
|
同第二篇中的一样,我们在模板中可以这样使用它:
1
2
|
<
p
>
Current
Time
is
:
{
{
current_time
(
)
}
}
<
/
p
>
<
p
>
Current
Day
is
:
{
{
current_time
(
"%Y-%m-%d"
)
}
}
<
/
p
>
|
Flask添加全局函数的方法是封装了对Jinja2环境变量的操作。上述添加”current_time”全局函数的方法,等同于下面的代码。
1
|
app
.
jinja_env
.
globals
[
'current_time'
]
=
current_time
|
我们在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
23
24
25
26
27
28
29
|
from
flask
import
Flask
,
render_template
app
=
Flask
(
__name__
)
@
app
.
route
(
'/hello'
)
@
app
.
route
(
'/hello/<name>'
)
def
hello
(
name
=
None
)
:
return
render_template
(
'hello-5.html'
,
name
=
name
)
########## Add Global Functions ##########
import
time
@
app
.
template_global
(
'current_time'
)
def
current_time
(
timeFormat
=
"%b %d, %Y - %H:%M:%S"
)
:
return
time
.
strftime
(
timeFormat
)
import
re
def
accept_pattern
(
pattern_str
)
:
pattern
=
re
.
compile
(
pattern_str
,
re
.
S
)
def
search
(
content
)
:
return
pattern
.
findall
(
content
)
return
dict
(
search
=
search
,
current_pattern
=
pattern_str
)
app
.
add_template_global
(
accept_pattern
,
'accept_pattern'
)
#app.jinja_env.globals['current_time'] = current_time
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
|
<
!
doctype
html
>
<
title
>
Hello
Sample
<
/
title
>
<style
type
="text/css">
.odd
{
background-color
:
#BDF
;
}
</style>
{
%
if
name
%
}
<
h1
>
Hello
{
{
name
}
}
!
<
/
h1
>
{
%
else
%
}
<
h1
>
Hello
World
!
<
/
h1
>
{
%
endif
%
}
{
%
set
cycle
=
cycler
(
'odd'
,
'even'
)
%
}
<
ul
>
{
%
for
num
in
range
(
10
,
20
,
2
)
%
}
<
li
class
=
"{{ cycle.next() }}"
>
Number
is
"{{ num }}"
,
next
line
is
"{{ cycle.current }}"
line
.
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
{
%
set
user
=
dict
(
name
=
'Mike'
,
age
=
15
)
%
}
<
p
>
{
{
user
|
tojson
|
safe
}
}
<
/
p
>
{
# 显示 '{"age": 15, "name": "Mike"}' #}
{
%
set
sep
=
joiner
(
"|"
)
%
}
{
%
for
val
in
range
(
5
)
%
}
{
{
sep
(
)
}
}
<
span
>
{
{
val
}
}
<
/
span
>
{
%
endfor
%
}
{
# 显示 "0 | 1 | 2 | 3 | 4" #}
<
p
>
Current
Time
is
:
{
{
current_time
(
)
}
}
<
/
p
>
<
p
>
Current
Day
is
:
{
{
current_time
(
"%Y-%m-%d"
)
}
}
<
/
p
>
{
%
with
pattern
=
accept_pattern
(
"<li>(.*?)</li>"
)
%
}
{
%
set
founds
=
pattern
.
search
(
"<li>Tom</li><li>Bob</li>"
)
%
}
<
ul
>
{
%
for
item
in
founds
%
}
<
li
>
Found
:
{
{
item
}
}
<
/
li
>
{
%
endfor
%
}
<
/
ul
>
<
p
>
Current
Pattern
:
{
{
pattern
.
current
_pattern
}
}
<
/
p
>
{
%
endwith
%
}
|
转载请注明:成长的对话 » Flask的Jinja2模板引擎 — 全局函数(5th)