Python+Flask.0014.FLASK模版相关之使用JinJa2模版渲染

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

简单 说明:

说明:  之前章节中,视图函数直接返回文本,而实际生产环境很少这样,因为实际的页面大多是带有样式和复杂逻辑的HTML+CSS+JS代码,这可以让浏览器渲染出非常漂亮和复杂的效果,页面内容应该是可以重用的,而且需要更执行更高级的功能

 

自带 模版:

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

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

from string import Template

# 说明: 导入其它模块

# 方式二: 自定义替换符以及匹配字符

class AtTemplate(Template):

    delimiter = r'@'

    idpattern = r'[_a-z][_a-z0-9]*'

if __name__ == '__main__':

    tp = Template('''

    name: $name

    age : $age

    ''')

    # 方式一: 默认替换符为$,匹配规则为[_a-z][_a-z0-9]*

    print tp.substitute(name=u'李满满', age=24)

    print tp.safe_substitute(name=u'刘珍珍', age=25)

    tp = AtTemplate('''

    name: @name

    age : @age

    ''')

    # 方式二: 自定义替换符为@匹配字符为[_a-z][_a-z0-9]*

    print tp.substitute(name=u'李满满', age=24)

    print tp.safe_substitute(name=u'刘珍珍', age=25)

说明: string.Template类,很简单的模版,支持有限,无法继承重用,这对于WEB开发远远不够,所以我们需要使用第三方专业模版系统,目前比较出名的是Jinja2和Mako模版系统

 

Jinja2模版:

1. 让页面逻辑独立于业务逻辑,开发的程序易于维护

2. 提供流程控制,继承等高级功能使得模版非常灵活,快速,安全

# API 使用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#!/usr/bin/env python

# -*- coding: utf-8 -*-

"""

#

# Authors: limanman

# OsChina: http://xmdevops.blog.51cto.com/

# Purpose:

#

"""

# 说明: 导入公共模块

from jinja2 import Template

# 说明: 导入其它模块

if __name__ == '__main__':

    # 说明: 渲染字符串

    template = Template('Hello {{ name }}!')

    print template.render(name=u'李满满')

说明: 由于单独拿API来使用不太常用,如果单独拿API使用的话掌握如上写法即可,和string.Template类用法基本一致,至于其它渲染指定文件可用读取成字符串再渲染,有兴趣可学习官方API文档

# 强大模版

1. 模版支持任何基于文本的格式(HTML/XML/CSV/LaTex等等),并没有特定的扩展名

# 基础语法

{%- ... -%}

说明: 主要解析流程控制等

{#-  ...  -#}

说明: 主要添加代码注释等

{{    ...    }}

说明: 主要解析模版表达式

# 数据类型

说明: 模版中支持字符串,数值,列表,元组,字典, boolean(true/false,注意是小写的),除此之外还支持全局函数/内置过滤器|/内置测试器is/in关键字/if关键字/字符连接符~

1. 支持算术运算符,+,-,/,//,%,*,**,

2. 支持比较运算符,==,!=,>,>=,<,<=

3. 支持逻辑运算符,and,or,not,(expr)

4. 支持其它运算符,in,is,|,~(连接字符串使用{{ 'hello ' ~ name ~ '!' }},如果name是limanman则返回hello limanman!),()调用可调用量,./[]获取对象属性

# 变量相关

1. 应用可将任意类型变量传递给模版,访问带属性变量既可以加.访问,也支持[]访问,两者的区别是查找的先后顺序,前者先加.测试,然后再[]测试,后者先[]测试然后在.测试,所以根据具体传递变量类型决定

2. 模版中中可以为变量赋值,在顶层的(块,宏,循环之外)赋值是可导出的,也就是说可以从别的模块儿中导入使用

1

2

{%- set navigation = [('index.html', 'Index'), ('about.html', 'About')] -%}

{%- set key, value =  call_something() -%}

# with语句

1. 模版中支持with语句,和PY内置with类似,with后面常跟表达式,主要用于限制对象的作用域

1

2

3

4

5

{% with arr=range(10) %}

    {% for i in arr %}

        {{ i }}

    {% endfor %}

{% endwith %}

# 过  滤 器

1. 过滤器和管道符|配合可链式修改变量,过滤器还支持传递参数,内置的过滤器列表可参考(http://docs.jinkan.org/docs/jinja2/templates.html#builtin-filters)

{{ v|abs }}

说明: 返回值的绝对值

{{ v|attr(name) }}

说明: 返回v对象的name属性值

{{ v|batch(linecount, fill_with=None) }}

说明: 将v序列linecount个元素分为一组,保证每组长度相同,如果不够用fill_with的值补充,常用于生成表格

1

2

3

4

5

6

7

8

9

10

<table width="600px" style="border-collapse: collapse;margin: 0 auto;" border="1">

    {%- for tr in table_tds|batch(10, " ") -%}

        <tr>

            {%- for td in tr -%}

                <td>{{ td }}td>

            {%- endfor -%}

        tr>

    {%- endfor -%}

table>

{{ v|capitalize }}

说明: 整个语句的首字母大写,其它字母小写

{{ v|default(default_value='', boolean=False) }}

说明: boolean为False,只有未定义时才返回default_value,boolean为True时,只要v为False就使用default_value.

{{ v|dictsort(case_sensitive=False, by='key') }}

说明: 对v字典进行排序case_sensitive设置是否大小写敏感,by指定键排序

{{ v|escape }}

说明: 对v进行安全转义,可以简写为e

{{ v|filesizeformat(binary=False) }}

说明: 格式化v为可读的文件大小默认以字节为单位

{{ v|first }}

说明: 返回序列对象的第一个元素

{{ v|float(default=0.0) }}

说明:转换value值为float类型,如果转换失败则返回default的值

{{ v|forceescape }}

说明: 不管v是否被转义过,一律进行html转义,可能会二次转义

{{ v|format(*args, **kwargs) }}

说明: 使用*args和**kwargs去填充格式化字符串v

{{ v|groupby(attr) }}

说明: 对序列v中的对象/字典按照attr分组,分组后组名存储在group.grouper里,而组员保存在group.list,如下是一个站点地图的简单实现

1

2

3

4

5

6

7

8

9

10

<ul>

    {%- for group in persons|groupby("gender") -%}

        <li>{{ group.grouper }}li>

        <ul>

            {%- for person in group.list -%}

                <li>{{ person['name'] }}, {{ person['age'] }}li>

            {%- endfor -%}

        ul>

    {%- endfor -%}

ul>

{{ vint(default=0) }}

说明: 将v的值转换为int如果转换失败返回default的值

{{ v|join(d='', attribute=None) }}

说明: 使用d分割符拼接v,如果attribute为字符串则首先获取value的attribute属性然后用d分割符去拼接属性值

{{ v|last }}

说明: 返回序列对象v的最后一个元素

{{ v|length }}

说明: 说明返回对象的长度

{{ v|list }}

说明: 转换v为列表,如果value为字符串则转换为字符列表

{{ v|lower }}

说明: 转换为小写

{{ v|map(filter/attribute='') }}

说明: filter过滤器作用域v的每个元素,attribute过滤出v中包含指定属性的元素

1

2

3

{%- for val_unit in  [1024, 2048, 4096]|map('filesizeformat') -%}

    <p>{{ val_unit }}p>

{%- endfor -%}

{{ v|pprint(verbose=False) }}

说明: 更优美的方式打印,用于调试

{{ v|random }}

说明: 从序列对象中随机返回一个元素

{{ v|replace(old, new, count=None) }}

说明: 将v中的old替换为new,如果指定了count定义替换n次

{{ v|reverse }}

说明: 反转value序列

{{ v|round(precision=0, method='common') }}

说明: 四舍五入v的值precision表示保留小数点几位,method的值可以为common/ceil/floor

{{ v|safe }}

说明: 标记value为安全字符串,按照正常规则去解析

{{ value|sort(reverse=False, case_sensitive=False, attribute=None) }}

说明: 如果指定attribute则按照attribute排序,reverse表示是否逆向排序,case_sensitive表示是否区分大小写

1

2

3

{%- for cur_item in data|sort(false, true, attribute='index') -%}

    <p>{{ cur_item['index'] }}p>

{%- endfor -%}

{{ v|string }}

说明: 将v对象转换为字符串

{{ v|striptags }}

说明: 清除v中的html/xml等文档中的标签

{{ v|sum(attribute=None, start=0) }}

说明: 如果设置了attribute则会获取v中所有元素的attribute属性的值的总和,start为初始值

{{ v|title }}

说明: 让v中的每个字母的首字母大写

{{ v|trim }}

说明: 去除v两边的空白

{{ v|truncate(length=255, kilwords=False, end='...') }}

说明: v字符串超过length长度的部分用...代替,如果要精确到字符的话需设置killwards为true,否则设置为false

{{ v|tojson|safe }}

说明: 将v转换为json,但是为了不被转义,常常配合safe在JavaScript脚本中使用

1

2

3

4

5

6

"text/javascript">

    var users = {{ users|tojson|safe }}

    for(var i=0; i

        console.log(users[i].name)

    }

{{ v|upper }}

说明: 把v中的所有字符转换为大写

{{ v|urlencode }}

说明: 将v进行URL编码

{{ v|urlize(trim_url_limit=None, nofollow=False) }}

说明: 转换v为可点击的url连接地址,trim_url_limit设置url显示的长度,超出长度用...填充

{{ v|wordcount }}

说明: 获取s中的单词的数量

2. 除了内置过滤器还支持自定义过滤器,非常简单可通过app.add_template_filter(func, name)函数或@@app.template_filter(name)修饰器来自定义过滤器,两种方法内部调用的都是app.jinja_env.filters[name] = func实现的,但并不推荐直接设置jinja2环境,所以还是推荐前两种方法

1

2

3

@monitor.app_template_filter('sub')

def sub_filter(inputs, start, end, step):

    return inputs[start:end:step]

# 测试相关

1. 测试用于对照普通表达式测试一个变量,内置的列表可参考(http://docs.jinkan.org/docs/jinja2/templates.html#builtin-tests)

{%- object is callable -%}

说明:测试object是否可以被调用

{%- value is defined -%}

说明:测试value是否被定义

{%- value is divisibleby(num) -%}

说明:测试value是否可被num整除

{%- value is escaped -%}

说明:测试value是否被转义过

{%- value is even -%}

说明:测试value是否为奇数

{%- value is iterable -%}

说明:测试value是否可迭代

{%- value is lower -%}

说明:测试value是否小写

{%- value is mapping -%}

说明:测试value是否是字典

{%- value is none -%}

说明:测试value是否为none

{%- value is number -%}

说明:测试value是否为字符串

{%- value is odd -%}

说明:测试value是否为奇数

{%- value is sequence -%}

说明:测试value是否是序列对象

{%- value is string -%}

说明:测试value是否为字符串

{%- value is undefined -%}

说明:测试value是否未定义

{%- value is upper -%}

说明:测试value是否为大写

2. 除了内置测试器还支持自定义测试器,非常简单,通过app.add_template_test(func, name)函数或@app.template_test(name)修饰器来自定义过滤器,两种方法内部调用的都是app.jinja_env.tests[name] = func实现的,但并不推荐直接设置jinja2环境,所以还是推荐前两种方法

1

2

3

@monitor.app_template_test('endswith')

def ends_width(s, suffix):

    return s.endswith(suffix)

# 全局函数

1. 如果说过滤器是一个变量转换函数,测试器是一个变了测试函数,那么全局函数就可以是任何函数,可以在任一场景使用,没有输入和输出值限制,全局函数可参考,http://docs.jinkan.org/docs/jinja2/templates.html#builtin-globals

range([start], stop[, step])

说明: 返回一个包含整等差级数的列表

dict(**items)

说明: 方便的字典替代品{'foo': 'bar'}等价于dict(foo=bar)

lipsum(n=5, html=True, min=20, max=100)

说明: 在模版中生成lipsum乱数假文,默认会生成5段html,每段20到100词之间,如果html被禁用,则会返回常规文本,在测试布局时生成简单内容时很有用

joiner(sep)

说明: 初始化一个分割符,第一次调用返回空字符,以后调用返回分割符,常用于分割循环中的内容

1

2

3

4

5

6

7

8

<ul>

    {%- set sep = joiner('|') -%}

    {%- for title in ['资产管理', '主机分组', '主机信息'] -%}

        {%- set s = '<i>' ~ sep() ~ 'i>' if sep() -%}

        {{ s|safe }}

        <li><a href="#">{{ title }}a>li>

    {% endfor %}

ul>

说明: 在模版中生成乱数假文,默认会生成5段html,每段在20到100词之间,如果HTML被禁用,会返回常规文本,在测试布局时生成简单内容很有用

cycler(*items)

说明: 周期性的从若干个值的循环,周期实例.next()返回当前项并跳到下一个,.reset()重置周期计到第一个项,.current返回当前项

1

2

3

4

5

6

7

8

9

10

11

{%- set cur_datas = range(1, 101, 1) -%}

{%- set row_class = cycler('light', 'dark') -%}

<table style="margin: 0 auto;border-collapse: collapse" width="600px" border="1">

    {%- for tr in cur_datas|slice(10) -%}

        <tr class="{{ row_class.next() }}">

            {%- for td in tr -%}

                <td>{{ td }}td>

            {%- endfor -%}

        tr>

    {%- endfor -%}

table>

join(sep=',')

说明: 连接多个项

1

{{ range(10)|join(',') }}

2.  除了内置全局函数还支持自定义全局函数,非常简单,通过app.add_template_global(func, name)函数或@app.template_global(name)修饰器来自定义全局函数,两种方法内部调用的都是app.jinja_env.globals[name] = func实现的,但并不推荐直接设置jinja2环境,所以还是推荐前两种方法

1

2

3

@monitor.app_template_global('endswith')

def ends_width(s, suffix):

    return s.endswith(suffix)

# 注释相关

1. 模版中注释默认使用{# ... #},可以注释多行,在调试或添加模版信息时非常有用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

{# 说明: 创建宽度为600px并居中对齐的一个10行10列的表格,并隔行换色

    <table style="margin: 0 auto;border-collapse: collapse" width="600px" border="1">

        {%- for tr in table_tds|slice(10) -%}

            {% if loop.index is odd %}

                <tr bgcolor="#ffffff">

                    {%- for td in tr -%}

                        <td>{{ td }}td>

                    {%- endfor -%}

                tr>

            {%- else -%}

                <tr bgcolor="#a9a9a9">

                    {%- for td in tr -%}

                        <td>{{ td }}td>

                    {%- endfor -%}

                tr>

            {%- endif -%}

        {%- endfor -%}

    table>

 #}

# 空白控制

1. 默认模版引擎不会对空白处理,所以模版中的代码块中的每个空白都会原封不动返回,可以通过{%- ... -%}手动剥离块前或块儿后的空白,但需要注意的是-和{% %}不能有空白,否则无效

1

2

3

{%- for num in range(10) -%}

    {{ num }}

{%- endfor -%}

说明: 如上加-剥离空白后返回的是0123456789,而没有加-会发现返回的是0 1 2 3 4 5 6 7 8 9,每个项都多出一个空白,强烈推荐大家养成加-的习惯

# 转义相关

1.单行可用{{ '{{}}' }}作为原始字符串实现转义,多行可使用raw(如展示Jinja2语法的实例)

1

2

3

4

5

6

<li>{{ '{{' }}li>

{% raw %}

    {% for item in seq %}

        <li>{{ item }}li>

    {% endfor %}

{% endraw %}

# 模版继承

1. Jinja2最强大的部分就是模版继承,模版继承允许你构建一个包含你站点公共元素的基本模版'骨架',并定义子模版可以覆盖的块

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<html {% block  html_attribs %}{%- endblock -%}>

{%- block html -%}    

    <head>

    {%- block head -%}    

        {% block meta %}

        {%- endblock -%}

        {% block styles %}

        {%- endblock -%}

    {%- endblock -%}    

    head>

    <body {%- block body_attribs -%}{%- endblock -%}>

    {%- block body -%}

        {%- block scripts -%}

        {%- endblock -%}

    {%- endblock -%}

    body>

{%- endblock -%}    

html>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

{%- extends 'base.html' -%}

{%- block head -%}

    {{ super() }}

    {#- 头部区 -#}

{%- endblock -%}

{%- block body -%}

    {{ super() }}

    {#- 主体区 -#}

{%- endblock -%}

{%- block styles -%}

    {{ super() }}

    {#- 样式区 -#}

{%- endblock -%}

{%- block scripts -%}

    {{ super() }}

    {#- 脚本区 -#}

{%- endblock -%}

说明: {% block ... %} ... {% endblock %}表示子模板需要填充的块,{% extends '....html' %}表示此模版继承自另一个模版,所以首先会定位父模版(应该作为第一个标签),默认继承时从templates目录查找,模版引擎也支持相对路径,但是需要注意的是同一个模版不能出现同名block,但是可以通过{{ self.block_name() }}在同一个页面调用指定的block块儿

# 嵌套相关

1. {%- block ... -%}{{ var }}{%- endblock -%}块内的变量var不允许访问块外作用域的变量,如果需要添可为block添加修饰scoped才可以获取块外的变量的值

# 控制结构

1. for可遍历可迭代对象中的每项,在模版循环体中支持特殊变量访问

loop.index

说明: 当前循环迭代的次数(从1开始)

loop.index0

说明: 当前循环迭代的次数(从0开始)

loop.revindex

说明: 到循环结束需要迭代的次数(从1开始)

loop.revindex0

说明: 到循环结束需要迭代的次数(从0开始)

loop.first

说明: 如果是第一次迭代,返回True

loop.last

说明: 如果是最后一次迭代,返回True

loop.length

说明: 序列中的项目数

loop.cycle

说明: 在一串序列周期间取值

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

{%- for cur_item in data -%}

    

总计需要循环的次数 : {{ loop.length }}</P>

    

从data中随机取数字: {{ loop.cycle(*data) }}</p>

    {%- if loop.first -%}

        

loop start ....</p>

    {%- endif -%}

    />

    

当前循环计数(1开始): {{ loop.index }}</p>

    

当前循环计数(0开始): {{ loop.index0 }}</p>

    

剩余循环计数(1开始): {{ loop.revindex }}</p>

    

剩余循环计数(0开始): {{ loop.revindex0 }}</p>

    {%- if loop.last -%}

        

loop end....</p>

    {%- endif -%}

{%- endfor -%}

说明: for循环中loop.cycle()辅助函数,伴随循环字符串/变量列表中周期取值

2. 模版中循环不支持break/continue,但支持联合if跳过,如果过滤了所有项目而没有执行循环可使用else渲染替换块儿

1

2

3

4

5

{%- for cur_item in data if cur_item is odd  -%}

    <p>{{ cur_item }}p>

{%- else -%}

    <p>nothingp>

{%- endfor -%}

3. 模版支持递归循环,常用在站点地图,要使用递归循环,需要在循环定义中加上recursive修饰,并在你想递归的地方调用loop变量

1

2

3

4

5

6

7

8

9

10

11

12

<ul>

    {%- for cur_link in links recursive -%}

        <li><a href="{{ cur_link['href'] }}">{{ cur_link['caption'] }}a>li>

        {%- if cur_link['children'] -%}

            <ul>

                {{ loop(cur_link['children']) }}

            ul>

        {%- endif -%}

    {% else %}

        <li>no item found.li>

    {% endfor %}

ul>

注意: 如上代码{{ loop( ... ) }}外层必须还要包括一个ul,不然递归循环时生成的li依然放在第一层的ul中,页面的结构会错乱

4. if语句可以用于内联表达式并作为循环过滤,而且支持用elif和else来构建多个分支

1

{% extends layout_template if layout_template is defined else 'master.html' %}

5. 宏类似常规编程语言中的函数,用于把常用的作为可重用函数,取代重复定义,如果需要宏在不同模版中引用需使用import导入,宏内部可以访问三个特殊变量

varargs

说明: 如果有多余宏位置参数,它们会作为列表的值保存在varargs变量上

kwargs

说明: 如果有多余宏键值参数,它们会作为列表的值保存在kwargs变量上

caller

说明: 如果宏通过call标签调用,调用者会作为可调用的宏存储在这个变量中

name

说明: 宏的名称

arguments

说明: 一个宏接受的参数名的元素

defaults

说明: 默认值的元素

catch_kwargs

说明: 如果宏接受额外的关键字参数,为True

catch_varargs

说明: 如果宏接受额外的位置参数,为True

caller

说明: 如果宏访问特殊的caller变量由call标签调用,为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

{%- macro list_user(users) -%}

    <table>

        <tr>

            <th>nameth>

            <th>optionth>

        tr>

        {%- for user in users -%}

            <tr>

                <td>{{ user.name }}td>

                <td>{{ caller(user.id) }}td>

            tr>

        {%- endfor -%}

    table>

{%- endmacro -%}

{%- block body -%}

    {%- set users = [

                        {'id': 1, 'name': '李满满'},

                        {'id': 2, 'name': '刘珍珍'},

                    ] -%}

    {%- call(id) list_user(users) -%}

        <a href="#user_edt#{{ id }}">编辑a>

        |

        <a href="#user_del#{{ id }}">删除a>

    {%- endcall -%}

{%- endblock -%}

注意:如果一个宏的名称以下划线开始,它无法被导入到其它模版,如上简单演示了macro宏利用caller()访问调用者内容的例子,caller()中可以添加参数也可以不添加参数,非常灵活

6. 宏常存放使用的代码,这些宏可以被导入,并在可通过import/from import导入但默认不传递到当前上下文,只作为宏的存放处,如果要实现类似include支持传递到当前上下文,需要结合with context

 

1

2

{% import 'forms.html' as forms with context %}

{% from 'forms.html' import input as input_field, textarea with context %}

 

# 语句过滤

说明: 过滤器filter可以调用所有jinja2的过滤器,包含在filter节中的数据都会被渲染

1

2

3

{%- filter upper -%}

    <p>All html contents will be uppercase.p>

{%- endfilter -%}

# INCLOUD

说明: incloud可以包含单个文件也可以包含一个文件列表,ignore missing可以忽略文件不存在导致的异常,with context时incloud包含的可渲染变量会自动被渲染,当然without context自然是禁用它

1

2

3

4

5

{% include "sidebar.html" ignore missing %}

{% include "sidebar.html" ignore missing with context %}

{% include "sidebar.html" ignore missing without context %}

{% include ['page_detailed.html', 'page.html'] %}

{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}

# 上下环境

说明: FLASK每个请求都有生命周期,请求会携带请求上下文,作为在请求中渲染的模版,自然也是在请求的声明周期内,所以FLASK的模版自然可以使用到请求上下文的环境变量,及一些辅助函数

1. 模版中支持请求对象request所有的属性和方法,但是需要注意的是在非请求上下中这个对象是不可用的

1

{{ request.url }}

2. 模版中支持会话对象session所有的属性和方法,但是需要注意的是在非请求上下中这个对象是不可用的

1

{{ session.user }}

3. 模版中支持全局对象g所有的属性和方法,但是需要注意的是在非程序或请求上下中这个对象是不可用的

1

{{ g.user }}

4. 模版中支持配置对象config所有的属性和方法,但是需要注意的是在非程序或请求上下中这个对象是不可用的

1

{{ config.DEBUG }}

5. 模版中支持url_for()函数,可以快速获取以及构建URL,FLASK也将此函数引入模版中

1

<a href="{{ url_for('monitor.index') }}">monitora>

6. 模版中还支持自定义上下文变量和函数,非常简单只需要用@app.context_processor去修饰一个返回字典的函数,字典中的键就可以在模版中直接使用,而字典中的可以是任何值,可以是变量可以是函数

1

2

3

4

5

6

7

8

9

@monitor.context_processor

def injection():

    area = u'国内'

    def hosts():

        return [h for in xrange(10)]

    return {

        'area': area,

        'hosts': hosts

    }

# 模版扩展

说明: 除了以上的功能外,JinJa2还支持扩展或插件开发,允许第三方通过开发新的扩展或插件,当然它自身也提供了一些扩展功能,只是默认没有开启,咱们只是简单讲下怎么启用扩展,至于怎么使用就自己看官网文档了~

1

2

3

4

5

6

7

8

extensions = ['jinja2.ext.autoescape',

         'jinja2.ext.with_',

         'jinja2.ext.do',

         'jinja2.ext.i18n',

         'jinja2.ext.loopcontrols']

jinja_env = Environment(extensions=extensions)

for extension in extensions:

    app.jinja_env.add_extension(extension)

 

 

登录乐搏学院官网http://www.learnbo.com/

或关注我们的官方微博微信,还有更多惊喜哦~

转载于:https://my.oschina.net/learnbo/blog/863904

你可能感兴趣的:(python,javascript,json,ViewUI)