编辑
2022-11-11
🧰语言-python
00
请注意,本文编写于 951 天前,最后修改于 225 天前,其中某些信息可能已经过时。

目录

0.什么叫做渲染?
1. if和for的用法
1.1 3种定界符
1.2 模板语法
1.3 过滤器
2.模板辅助工具
2.1自定义上下文
2.2自定义全局函数
2.3自定义过滤器
2.4 测试器
2.5 模板环境对象
1.添加自定义全局对象
2.添加自定义过滤器
3.添加自定义测试器
3.模板结构组织
3.1局部模板
3.2 宏
3.3 模板继承
4. 模板进阶实践
4.1 空白控制
4.2 加载静态文件

0.什么叫做渲染?

模板引擎的作用就是读取并执行模板中的特殊语法标记,并根据传入的数据将变量替换为实际值,输出最终的HTML页面,这个过程被称为渲染(rendering)。

flask默认使用的模板为Jinja2,它是一个功能齐全的Python模板引擎,除了设置变量,还允许我们在模板中添加if判断,执行for迭代,调用函数等,以各种方式控制模板输出。

1. 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>

1.1 3种定界符

  • 语句,比如if判断、for循环等。
{%……%}
  • 表达式,比如字符串、变量、函数调用等。
{{……}}
  • 注释
{#……#}

1.2 模板语法

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序列包含的元素数量

1.3 过滤器

过滤器是一些可以用来修改和过滤变量值的特殊函数,过滤器和变量用一个竖线隔开,需要参数的过滤可以像函数一样使用括号传递。

{{ name|title }}

相当于Python里调用name.title().

另一种方法是将过滤器作用于一部分模板数据,使用filter标签和endfilter标签声明开始和结束。

比如下面使用upper过滤器将一段文字转换为大写:

{% filter upper%} This text become uppercase {% endfilter %}

2.模板辅助工具

除了在渲染的时候传入变量,也可以在模板中定义变量,使用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 %}

2.1自定义上下文

如果多个模板都需要使用同一变量,那么比起在多个视图函数中重复传入,更好的方式是能够设置一个模板全局变量。

Flask提供了一个app.context_processor装饰器,可以用来注册模板上下文处理函数,它可以帮我们完成统一传入变量的工作。

@app.context_processor def inject_foo(): foo = 'I am a foo.' return dict(foo=foo)

接下来,你就可以直接在Html中调用:

{{foo}}

2.2自定义全局函数

我们可以使用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}}

2.3自定义过滤器

使用app.template_filter()装饰器可以注册自定义过滤器

from flask import Markup @app.template_filter() def muiscal(s): return s+Markup('&#9835;')

2.4 测试器

用法:

{% 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

2.5 模板环境对象

在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 = ']]'

1.添加自定义全局对象

def bar(): return 'I am bar.' foo = ' I am foo.'' app.jinja_env.globals['bar'] = bar app.jinja_env.globals['foo'] = foo

2.添加自定义过滤器

def smiling(s): return s+ ':)' app.jinja_env.filters['smiling'] = smiling

3.添加自定义测试器

def baz(n): if n =='baz': return True return False app.jinja_env.tests['baz'] = baz

3.模板结构组织

3.1局部模板

我们使用include标签来插入一个局部模板,这会把局部模板的全部内容插在使用include标签的位置。

比如,在其他模板中,我们可以在任意位置使用下面的代码插入__banner.html的内容。

{% include '_banner.html' %}

3.2 宏

宏(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的模板上下文包含下列对象。

  • Flask使用内置的模板上下文处理函数提供的g、session、config、request
  • 扩展使用内置的模板上下文处理函数提供的变量
  • 自定义模板上下文处理器传入的变量
  • 使用render_template()函数传入的变量
  • Jinja2 和Flask内置及自定义全局对象
  • Jinja2内置自定义过滤器
  • Jinja2内置自定义测试器

使用include标签插入的局部模板包含下列对象:

  • Jinja2和Flask内置的全局函数和自定义全局函数
  • Jinja2内置及自定义过滤器
  • Jinja2内置及自定义测试器

因此,如果我们想在导入的宏中使用第一个列表中的2、3、4项,就需要在导入时显式地使用with context 声明传入当前模板的上下文:

{% from "macros.html" import foo with context %}

3.3 模板继承

编写基模板 基模板存储了程序页面的固定部分,通常被命名为base.html或layout.html。

块的开始和结束分别使用block和endblock标签声明,而且块之间可以嵌套。

在这个基模板中,我们创建了六个块head、title、styles、content、footer和scripts

(1)覆盖内容

当在子模板里创建同名的块时,会使用子块的内容覆盖父块的内容。

(2)追加内容

需要使用super()函数进行声明。

{% block styles %} {{ super() }} <style> .foo{ color:red; } </style> {% endblock %}

4. 模板进阶实践

4.1 空白控制

如果你想在渲染时自动去掉这些空行,可以在定界符内添加减号。

比如,{%-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

宏内的空白不受控制,需要加-号

4.2 加载静态文件

<img src ="{{url_for('static',filename='avatar.jpg')}} " width="50">

本文作者:Eric

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!