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。
由此可见,全局函数如同其名字一样,就是全局范围内可以被使用的函数。其同第二篇介绍的上下文环境中定义的函数不同,没有请求生命周期的限制。
演示几个常用的内置全局函数。
1 2 3 4 | { % set user = dict ( name = ‘Mike’ , age = 15 ) % } < p > { { user | tojson | safe } } < / p > { # 显示 ‘{“age”: 15, “name”: “Mike”}’ #} |
1 2 3 4 5 6 | { % set sep = joiner ( “|” ) % } { % for val in range ( 5 ) % } { { sep ( ) } } < span > { { val } } < / span > { % endfor % } { # 显示 “0 | 1 | 2 | 3 | 4” #} |
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()”函数返回的对象可以做如下操作
更全的内置全局函数介绍可以从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 % } |
文章转载来自:trustauth.cn