模板引擎的作用就是读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,输出最终的HTML页面,这个过程被称为渲染(rendering)。
flask默认使用的模板为Jinja2,它是一个功能齐全的Python模板引擎,除了设置变量,还允许我们在模板中添加if判断,执行for迭代,调用函数等,以各种方式控制模板输出。
<div class="layui-inline"> <label class="layui-form-label" for="search_s">子类</label> <div class="layui-input-inline"> <select name="father" id="search_s"> <option style='display: none'></option> {%for son in sons%} {% if '——' not in son%} <option name="count_type_s" value="{{son}}">{{son}}</option> {%endif%} {% endfor %} </select> </div>
{%……%}
{{……}}
{#……#}
Jinja2允许你在模板中使用大部分Python对象,比如字符串、列表、字典、元组、整型、浮点型、布尔值。
它支持其他基本的运算符号(加减乘除)、比较符号 == !=、逻辑符号(and or not 和括号)以及in、is、None和布尔值。
常用的Jinja2 for循环特殊变量
变量名 | 说明 |
---|---|
loop.index | 当前迭代数字,从1开始 |
loop.index() | 当前迭代数字,从0开始 |
loop.reindex | 当前反向迭代数,从1开始 |
loop.reindex() | 当前反向迭代数,从0开始 |
loop.first | 如果是第一个元素,则为True |
loop.last | 如果是最后一个元素,则为True |
loop.previtem | 上一个迭代的条目 |
loop.nextitem | 下一个迭代的条目 |
loop.length | 序列包含的元素数量 |
过滤器是一些可以用来修改和过滤变量值的特殊函数,过滤器和变量用一个竖线隔开,需要参数的过滤可以像函数一样使用括号传递。
{{ name|title }}
相当于Python里调用name.title().
另一种方法是将过滤器作用于一部分模板数据,使用filter标签和endfilter标签声明开始和结束。
比如下面使用upper过滤器将一段文字转换为大写:
{% filter upper%} This text become uppercase {% endfilter %}
除了在渲染的时候传入变量,也可以在模板中定义变量,使用set标签(set的作用就是定义变量,是全局变量):
{% set navigation = [('/','Home'),('/about','About')]%}
with定义的是局部变量
{% with username = '局部变量'%} {% endwith %}
你也可以将一部分模板数据定义为变量,使用set和endset标签声明开始和结束:
{% set navigation%} <li><a href = "/">Home</a> <li><a href ="/about">About</a> {% endset %}
如果多个模板都需要使用同一变量,那么比起在多个视图函数中重复传入,更好的方式是能够设置一个模板全局变量。
Flask提供了一个app.context_processor装饰器,可以用来注册模板上下文处理函数,它可以帮我们完成统一传入变量的工作。
@app.context_processor def inject_foo(): foo = 'I am a foo.' return dict(foo=foo)
接下来,你就可以直接在Html中调用:
{{foo}}
我们可以使用app.template_global装饰器直接将函数注册为模板全局函数。
@app.template_global() def bar(): return 'I am bar.'
默认使用函数的原名称传入模板,在app.template_global装饰器中使用name参数可以指定一个自定义名称。
内置过滤器
过滤器 | 说明 |
---|---|
default(value,default_value=u'',boolean=False) | 设置默认值,默认值作为参数传入,别名为d |
escape(s) | 转义Html文本,别名为e |
first(eq) | 返回序列的第一个元素 |
last(eq) | 返回序列的最后一个元素 |
length(eq) | 返回变量的长度 |
random(eq) | 返回序列中的随机元素 |
safe(value) | 将变量值标记为安全,避免转义 |
trim(value) | 清楚变量值前后的空格 |
max(value,case_sensitive=False,attribute=None) | 返回序列中的最大值 |
min(value,case_sensitive=False,attribute=None) | 返回序列中的最小值 |
unique(value,case_sensitive=False,attribute=None) | 返回序列中的不重复的值 |
striptags(value) | 清楚变量值内的Html标签 |
urlize(value,trim_url_limit=None,nofollow=False,target=None,rel=None) | 将url文本转换为可单击的HTML链接 |
wordcount(s) | 计算单词数量 |
tojson(value,indent=None) | 将变量值转换为Json格式 |
truncate(s,length=225,killwords=False,end='……',leeway=None) | 截断字符串,常用于文章摘要,lenght参数设置截断的长度,killwords参数设置是否阶段单词,end参数设置结尾的符号 |
在使用过滤器时,列表中过滤器函数的第一个参数表示被过滤的变量值或字符串,即竖线符号左侧的值,其他的参数可以通过添加括号传入。
<h1>hello,{{name|default('陌生人')|title}}!</h1>
XSS攻击的主要防范措施,其中最主要的是对用户输入的文本进行转义。
根据Flask设置,Jinja2会自动对模板中的变量进行转义,所以我们不用手动使用escape过滤器或调用escape()函数对变量进行转义。
如果你想避免转义,将变量作为HTML解析,可以对变量使用safe过滤器:
{{ sanitized_text|safe}}
另一种将文本标记为安全的方法是在渲染前将变量转换为Markup对象。
from flask import Markup @app.route('/hello') def hello(): text = Markup('<h1>Hello,Flask!</h1>') return render_template('index.html',text=text)
这时在模板中可以直接使用{{text}}
使用app.template_filter()装饰器可以注册自定义过滤器
from flask import Markup @app.template_filter() def muiscal(s): return s+Markup('♫')
用法:
{% if age is number %} {{ age*365 }} {% else %} 无效的数字 {% endif %}
内置测试器
测试器 | 说明 |
---|---|
callable(object) | 判断对象是否可被调用 |
defined(value) | 判断变量是否已定义 |
undefined(value) | 判断变量是否未定义 |
none(value) | 判断变量是否为None |
number(value) | 判断变量是否为数字 |
string(value) | 判断变量是否为字符串 |
sequence(value) | 判断变量是否是序列,比如字符串、列表、元组 |
iterable(value) | 判断变量是否迭代 |
mapping(value) | 判断变量是否是匹配对象,比如字典 |
sameas(value,other) | 判断变量与other是否指向相同的内存地址 |
自定义测试器
@app.template_text() def baz(n): if n=='baz': return True return False
在Jinja2中,渲染行为有Jinja2.Environment类控制,所有的配置选项、上下文变量、全局函数、过滤器和测试器都存储在Environment实例上。
当与Flask结合后,我们并不单独创建Environment对象,而是使用Flask创建的Envirment对象,它存储在app.jinja_env的属性上。
在程序中,我们可以使用app.jinja_env更改jinja2设置,比如,可以自定义所有的定界符。
app = Flask(__name__) app.jinja_env.variable_start_string=''[[' app.jinja_env.variable_end_string = ']]'
def bar(): return 'I am bar.' foo = ' I am foo.'' app.jinja_env.globals['bar'] = bar app.jinja_env.globals['foo'] = foo
def smiling(s): return s+ ':)' app.jinja_env.filters['smiling'] = smiling
def baz(n): if n =='baz': return True return False app.jinja_env.tests['baz'] = baz
我们使用include标签来插入一个局部模板,这会把局部模板的全部内容插在使用include标签的位置。
比如,在其他模板中,我们可以在任意位置使用下面的代码插入__banner.html的内容。
{% include '_banner.html' %}
宏(macro)是Jinja2提供的一个非常有用的特性,类似Python中的函数。
使用宏可以把一部分模板代码封装到宏里,使用传递的参数来构建内容,最后返回构建后的内容。
为了方便管理,我们可以把宏存储在单独的文件中,这个文件通常命名为macros.html或_macors.html。
在创建宏时,我们使用macro和endmacro标签声明宏的开始和结束。在开始标签中定义宏的名称和接受的参数,例如:
{% macro qux(amount=1)%} {% if amount ==1%} I am qux. {% elif amout >1%} We are quxs. {% endif %} {% endmacro %}
使用时,需要像从Python模块中导入函数一样使用import语句导入它,然后作为函数调用,传入必要的参数,如下所示:
{% from 'macros.html' import qux%} …… {% qux(amout=5)%}
在Jinja2中,默认情况下包含(include)一个局部模板会传递当前上下文到局部模板中,但导入(import )却不会。 具体来说,当我们使用render_tempate()函数渲染一个foo.html的模板时,这个foo.html的模板上下文包含下列对象。
使用include标签插入的局部模板包含下列对象:
因此,如果我们想在导入的宏中使用第一个列表中的2、3、4项,就需要在导入时显式地使用with context 声明传入当前模板的上下文:
{% from "macros.html" import foo with context %}
编写基模板 基模板存储了程序页面的固定部分,通常被命名为base.html或layout.html。
块的开始和结束分别使用block和endblock标签声明,而且块之间可以嵌套。
在这个基模板中,我们创建了六个块head、title、styles、content、footer和scripts
(1)覆盖内容
当在子模板里创建同名的块时,会使用子块的内容覆盖父块的内容。
(2)追加内容
需要使用super()函数进行声明。
{% block styles %} {{ super() }} <style> .foo{ color:red; } </style> {% endblock %}
如果你想在渲染时自动去掉这些空行,可以在定界符内添加减号。
比如,{%-endfor%}会移除该语句前的空白,同理,在右边的边界符内测添加减号将移除该语句后的空白。
{% if user.bio -%} <i> This user has not provided a bio.</i> {% else -%} <i> This user has not provided a bio.</i> {%- endif %}
除了再模板中使用减号来控制空白外,我们也可以使用模板环境对象提供的trim_blocks和lstrip_blocks属性设置,前者用来删除Jinja2语句后的第一个空行,后者用来删除Jinja2语句所在行之前的空格和制表符:
app.jinja_env.trim_blocks = True app.jinja_env.lstrip_blocks = True
宏内的空白不受控制,需要加-号
<img src ="{{url_for('static',filename='avatar.jpg')}} " width="50">
本文作者:Eric
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!