所了解的模板引擎大部分都会提供类似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后,只显示”…”,截取部分也不出现;第三个是省略符号,默认是”…”。
其实从例子中我们可以猜到,过滤器本质上就是一个转换函数,它的第一个参数就是待过滤的变量,在模板中使用时可以省略去。如果它有第二个参数,模板中就必须传进去。
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提供了一个内置过滤器”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 > |
文章转载来自:trustauth.cn