在前面的示例中,视图函数的主要作用是生成请求的响应,这是最简单的请求。实际上,视图函数有两个作用:处理业务逻辑和返回响应内容。在大型应用中,把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本。本节学到的模板,它的作用即是承担视图函数的另一个作用,即返回响应内容。 模板其实是一个包含响应文本的文件,其中用占位符(变量)表示动态部分,告诉模板引擎其具体值需要从使用的数据中获取。使用真实值替换变量,再返回最终得到的字符串,这个过程称为“渲染”。Flask使用Jinja2这个模板引擎来渲染模板。Jinja2能识别所有类型的变量,包括{}。 Jinja2模板引擎,Flask提供的render_template函数封装了该模板引擎,render_template函数的第一个参数是要渲染的模板的文件名,后面的参数可以是键值对,也可以是**kwargs,均能将变量对应的真实值传递给模板。。

我们先来认识下模板的基本语法:

{% if user %}
{{ user }}
{% else %}
hello!
<ul>
{% for index in indexs %}
<li> {{ index }} </li>
{% endfor %}
</ul>

一、变量

Jinja2 模版中的变量代码块可以是任意 Python 类型或者对象,只要它能够被 Python 的 str() 方法转换为一个字符串就可以。

视图代码

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def index():
"""
"index.html"表示要渲染的模板
两种传递参数值的方式:
1、键值对
2、不定长字段参数**kwargs
"""
data = {
"name2": "李四",
"age2": 19
}
my_dict = {
"name": "王五",
"age": 21
}
my_list = [1, 2, 3, 4, 5, 6, 7]
list_index = 1
return render_template("index.html",
# 键值对
name1="张三", age1=18,
# 不定长参数
**data,
# 参数值除了可以是string和int类型外,还可以是dict,list等类型,只要这个类型能被 str() 方法转换为一个字符串就可以。
# dict类型
mydict=my_dict,
# list类型
mylist=my_list,
index=list_index
) if __name__ == '__main__':
app.run()

模板代码

模板放在templates目录下,名字为index.html。使用 {{ 参数名 }} 的方式进行插值操作。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- string 和 int取值方式 -->
<div>{{ name1 }}:{{ age1 }}</div>
<div>{{ name2 }}:{{ age2 }}</div> <!-- dict取值方式 -->
<div>{{ mydict }}</div>
<div>{{ mydict["name"]}}:{{ mydict.age }}</div> <!-- list取值方式 -->
<div>{{ mylist }}</div>
<div>{{ mylist[0] }}</div>
<div>{{ mylist[index] }}</div> </body>
</html>

渲染效果

二、过滤器

过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,而在模板中是不能直接调用 Python 中的某些方法,那么这就用到了过滤器。

过滤器的使用方式为:变量名 | 过滤器。 过滤器名写在变量名后面,中间用 | 分隔。如:{{variable | capitalize}},这个过滤器的作用:把变量variable的值的首字母转换为大写,其他字母转换为小写。

字符串过滤器

safe:禁用转义html标签
<p>{{ '<em>hello</em>' | safe }}</p> capitalize:把变量值的首字母转成大写,其余字母转小写
<p>{{ 'hello' | capitalize }}</p> lower:把值转成小写
<p>{{ 'HELLO' | lower }}</p> upper:把值转成大写
<p>{{ 'hello' | upper }}</p> title:把值中的每个单词的首字母都转成大写
<p>{{ 'hello' | title }}</p> reverse:字符串反转
<p>{{ 'olleh' | reverse }}</p> format:格式化输出
<p>{{ '%s is %d' | format('name',17) }}</p> striptags:渲染之前把值中所有的HTML标签都删掉
<p>{{ '<em>hello</em>' | striptags }}</p> truncate: 字符串截断
<p>{{ 'hello every one' | truncate(9)}}</p>

列表过滤器

irst:取第一个元素
<p>{{ [1,2,3,4,5,6] | first }}</p> last:取最后一个元素
<p>{{ [1,2,3,4,5,6] | last }}</p> length:获取列表长度
<p>{{ [1,2,3,4,5,6] | length }}</p> sum:列表求和
<p>{{ [1,2,3,4,5,6] | sum }}</p> sort:列表排序
<p>{{ [6,2,3,1,5,4] | sort }}</p>

语句块过滤(不常用)

{% filter upper %}
this is a Flask Jinja2 introduction
{% endfilter %}

自定义过滤器

过滤器的本质是函数。当模板内置的过滤器不能满足需求,可以自定义过滤器。

自定义过滤器有两种实现方式:

  • 使用Flask应用对象的add_template_filter方法
  • 使用Flask应用对象的template_filter装饰器

注意,自定义的过滤器名称如果和内置的过滤器重名,会覆盖内置的过滤器。

实现方式一:通过调用应用程序实例的add_template_filter方法实现自定义过滤器。该方法第一个参数是函数名,第二个参数是自定义的过滤器名称。

# 间隔截取列表
def filter_double_sort(ls):
return ls[::2] # 第一个参数为过滤器函数,
# 第二个参数为模板中使用的过滤器名字)
app.add_template_filter(filter_double_sort, 'double_2')

实现方式二:使用Flask应用对象的template_filter装饰器实现自定义过滤器。装饰器传入的参数是自定义的过滤器名称。

# 装饰器中的参数为模板中使用的过滤器名字
@app.template_filter('db2')
def filter_double_sort(ls):
return ls[::2]

使用自定义过滤器

<p>add_template_filter函数:{{ mylist | double_2 }}</p>
<p>template_filter装饰器:{{ mylist | db2}}</p>

三、Flask-WTF表单扩展

在介绍Flask-WTF表单扩展前,我们先不使用Flask-WTF简单实现一个注册表单

模板文件如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- form标签不使用action属性时,发送的请求被当前视图函数接收 -->
<form method='post'>
<div><input type="text" name="username" placeholder='用户名'></div>
<div><input type="password" name="password" placeholder='密码'></div>
<div><input type="password" name="password2" placeholder='确认密码'></div>
<input type="submit">
</form>
</body>
</html>

视图函数如下:

from flask import Flask, render_template, request, session, redirect, url_for

app = Flask(__name__)
app.config["SECRET_KEY"] = "asd" @app.route("/login/")
def login():
return F"{session.get('user')} 注册成功" @app.route("/register/", methods=["get", "post"])
def register():
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
password2 = request.form.get("password2")
session["user"] = username
return redirect(url_for("login"))
else:
return render_template("register.html") if __name__ == '__main__':
app.run()

测试效果:

上图中,即使密码与确认密码不一致,但仍能注册成功,这是因为我们没有在视图中验证表单的数据,为了保证参数的合规性,我们需要对每个使用if来进行校验,这是很繁琐的。

而Flask-WTF扩展不仅可以帮助我们在视图中验证表单的数据,还可以使用该扩展进行CSRF验证,帮助我们快速定义表单模板。

使用Flask-WTF表单扩展,需要自行安装,安装命令如下:

pip install flask-wtf

并且还需要配置参数SECRET_KEY,当CSRF(跨站请求伪造)保护激活的时候,CSRF_ENABLED设置会根据设置的密匙生成加密令牌。

接下来,我们使用Flask-WTF实现表单。

模板文件如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
<!-- 设置csrf_token -->
{{ form.csrf_token }} {{ form.user_name.label }}
<p>{{form.user_name}}</p>
{% for msg in form.user_name.errors %}
<p>{{msg}}</p>
{% endfor %} {{ form.password.label }}
<p>{{form.password}}</p>
{% for msg in form.password.errors %}
<p>{{msg}}</p>
{% endfor %} {{ form.password2.label }}
<p>{{form.password2}}</p>
{% for msg in form.password2.errors %}
<p>{{msg}}</p>
{% endfor %} {{form.submit}}
</form>
</body>
</html>

视图函数如下:

from flask import Flask,render_template, redirect,url_for,session,request,flash

# 导入wtf扩展的表单类
from flask_wtf import FlaskForm
# 导入自定义表单需要的字段
from wtforms import SubmitField, StringField, PasswordField
# 导入wtf扩展提供的表单验证器的验证函数
from wtforms.validators import DataRequired, EqualTo app = Flask(__name__)
app.config['SECRET_KEY'] = 'asd' @app.route("/login/")
def login():
return F"{session.get('user')} 注册成功" # 定义注册表单类,该类继承FlaskForm
class RegisterForm(FlaskForm):
# 字段类型:
# StringField 对应 type="text"
# PasswordField 对应 type="password"
# SubmitField 对应 type="submit"
# 字段参数说明:
# label:字段的名称
# validators:验证器
# DataRequired(message):验证数据不能为空。message为校验不通过的提示
# EqualTo(fieldname, message):验证与指定字段fieldname的值相等,message为校验不通过的提示。
user_name = StringField(label=u"用户名", validators=[DataRequired(u"用户名不能为空")])
password = PasswordField(label=u"密码", validators=[DataRequired(u"密码不能为空")])
password2 = PasswordField(label=u"确认密码", validators=[DataRequired(u"确认密码不能为空"),
EqualTo("password", u"两次密码不一致")])
submit = SubmitField(label=u"提交") # 定义根路由视图函数,生成表单对象,获取表单数据,进行表单数据验证
@app.route('/register/', methods=['GET', 'POST'])
def register():
# 创建表单对象, 如果是post请求,前端发送了数据,flask会把数据在构造form对象的时候,存放到对象中
form = RegisterForm() # 判断form中的数据是否合理
# 如果form中的数据完全满足所有的验证器,则返回True,否则返回False
if form.validate_on_submit():
# 表示验证合格
# 提取数据
uname = form.user_name.data
pwd = form.password.data
pwd2 = form.password2.data
print(uname, pwd, pwd2)
session["user"] = uname
return redirect(url_for("login"))
# 如果校验为False,则返回模板数据
return render_template("register.html", form=form) if __name__ == '__main__':
app.run(debug=True)

测试效果:

WTForms支持的HTML标准字段

字段对象 说明
StringField 文本字段
TextAreaField 多行文本字段
PasswordField 密码文本字段
HiddenField 隐藏文本字段
DateField 文本字段,值为datetime.date格式
DateTimeField 文本字段,值为datetime.datetime格式
IntegerField 文本字段,值为整数
DecimalField 文本字段,值为decimal.Decimal
FloatField 文本字段,值为浮点数
BooleanField 复选框,值为True和False
RadioField 一组单选框
SelectField 下拉列表
SelectMultipleField 下拉列表,可选择多个值
FileField 文本上传字段
SubmitField 表单提交按钮
FormField 把表单作为字段嵌入另一个表单
FieldList 一组指定类型的字段

WTForms常用验证函数

验证函数 说明
DataRequired 确保字段中有数据
EqualTo 比较两个字段的值,常用于比较两次密码输入
Length 验证输入的字符串长度
NumberRange 验证输入的值在数字范围内
URL 验证URL
AnyOf 验证输入值在可选列表中
NoneOf 验证输入值不在可选列表中

四、控制语句

模板中的if控制语句

@app.route('/user')
def user():
user = 'flsk'
return render_template('user.html',user=user)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if user %}
<h1> hello {{user}} </h1>
{% else %}
<h1> welcome to flask </h1>
{% endif %}
</body>
</html>

模板中的for循环语句

 @app.route('/loop')
def loop():
fruit = ['apple','orange','pear','grape']
return render_template('loop.html',fruit=fruit)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
{% for index in fruit %}
<li>{{ index }}</li>
{% endfor %}
</ul>
</body>
</html>

五、宏、继承、包含

5.1 宏

类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余。

Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复。

定义宏

{% macro input() %}
<input type="text"
name="username"
value=""
size="30"/>
{% endmacro %}

调用宏

{{ input() }}

定义带参数的宏

{% macro input(name,value='',type='text',size=20) %}
<input type="{{ type }}"
name="{{ name }}"
value="{{ value }}"
size="{{ size }}"/>
{% endmacro %}

调用宏,并传递参数

{{ input(value='name',type='password',size=40)}}

把宏单独抽取出来,封装成html文件,其它模板中导入使用

文件名可以自定义,比如:定义macro.html,文件内代码如下

{% macro function() %}
<input type="text" name="username" placeholde="Username">
<input type="password" name="password" placeholde="Password">
<input type="submit">
{% endmacro %}

在其它模板文件中先导入,再调用

{% import 'macro.html' as func %}
{% func.function() %}

5.2 继承

模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。

{% block top %}``{% endblock %}标签定义的内容,相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。

子模板使用extends指令声明这个模板继承自哪?父模板中定义的块在子模板中被重新定义,在子模板中调用父模板的内容可以使用super()。

父模板:base.html

  {% block top %}
顶部菜单
{% endblock top %} {% block content %}
{% endblock content %} {% block bottom %}
底部
{% endblock bottom %}

子模板:

  {% extends 'base.html' %}
{% block content %}
需要填充的内容
{% endblock content %}

模板继承使用时注意点:

  • 不支持多继承。
  • 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
  • 不能在一个模板文件中定义多个相同名字的block标签。
  • 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。

5.3 包含(Include)

Jinja2模板中,除了宏和继承,还支持一种代码重用的功能,叫包含(Include)。它的功能是将另一个模板整个加载到当前模板中,并直接渲染。

示例:include的使用

{\% include 'hello.html' %}

包含在使用时,如果包含的模板文件不存在时,程序会抛出TemplateNotFound异常,可以加上ignore missing关键字。如果包含的模板文件不存在,会忽略这条include语句。

示例:include的使用加上关键字ignore missing

{\% include 'hello.html' ignore missing %}

5.4 宏、继承、包含

  • 宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。
  • 继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。
  • 宏(Macro)的功能类似函数,可以传入参数,需要定义、调用。
  • 包含(include)是直接将目标模板文件整个渲染出来。

Flask_Jinja2模板(九)的更多相关文章

  1. Sharepoint2013搜索学习笔记之自定义结果显示模板(九)

    搜索结果通过套用定义好的显示模板来展示结果,显示模板由js和html组成,我们可以通过修改显示模板,然后将修改好的显示模板跟搜索结果绑定起来,来修改搜索结果的显示效果,例子如下图: 修改前 修改后 第 ...

  2. PowerPoint基础

    一.基础 默认后缀ppt,pptx office2003和以后的版本只支持ppt, 可以将pptx另存为ppt97-2003 二.修改PPT尺寸 三.新建幻灯片 四.字体与段落设置 五.主题与字体 六 ...

  3. [转载]SharePoint 2013搜索学习笔记之自定义结果源

    搜索中心新建好之后在搜索结果页上会默认有所有内容,人员,对话,视频这四个结果分类,每个分类会返回指定范围的搜索结果,这里我再添加了部门日志结果分类,搜索这个分类只会返回部门日志内容类型的搜索结果,要实 ...

  4. zabbix自动发现监控mysql

    一. 数据库给只读权限 1.1 grant usage on *.* to 'zabbix'@'127.0.0.1' identified by 'zabbix'; flush privileges; ...

  5. zabbix主机自动注册

    一.主机自动注册的流程 zabbix agent指定server active主动自己的信息提供给zabbix_server,zabbix_server根据提供的信息自动添加主机,方便. 二. lin ...

  6. 学习Microsoft Visio(1)

    基础篇 一.认识Visio 1.Visio是什么 Visio最初属于Visio公司,该公司成立于1990年9月.1992年,公司更名为Shapeware.同年11月,它发布了他们公司的第一个产品:Vi ...

  7. ApacheCN PythonWeb 译文集 20211110 更新

    Django By Example 中文版 1 创建一个博客应用 2 为博客添加高级功能 3 扩展你的博客应用 4 创建一个社交网站 5 分享内容到你的网站 6 跟踪用户动作 7 构建在线商店 8 管 ...

  8. ApacheCN PythonWeb 译文集 20211028 更新

    Django By Example 中文版 1 创建一个博客应用 2 为博客添加高级功能 3 扩展你的博客应用 4 创建一个社交网站 5 分享内容到你的网站 6 跟踪用户动作 7 构建在线商店 8 管 ...

  9. ThinkPHP框架视图详细介绍 View 视图--模板(九)

    原文:ThinkPHP框架视图详细介绍 View 视图--模板(九) 视图也是ThinkPHP使用的核心部分: 一.模板的使用 a.规则 模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和 ...

随机推荐

  1. js 长按鼠标左键实现溢出内容左右滚动滚动

    var nextPress, prevPress; // 鼠标按下执行定时器,每0.1秒向左移一个li内容的宽度 function nextDown() { nextPress = setInterv ...

  2. idea集成开发工具快捷键大全

    1  执行(run)                                                 alt+r 2  提示补全 (Class Name Completion)    ...

  3. 删除空行(嵌套)(Power Query 之 M 语言)

    数据源: "姓名""基数""个人比例""个人缴纳""公司比例""公司缴纳"&qu ...

  4. CF158A Next Round 题解

    Content 有 \(n\) 个人参加比赛,第 \(i\) 名在第一轮的分数是 \(a_i\)(保证 \(a_i\geqslant a_{i+1}\))已知下一轮预计能进 \(k\) 人,当然如果有 ...

  5. CF289B Polo the Penguin and Matrix 题解

    Content 有一个 \(n\times m\) 的矩阵 \(A\),每次操作你可以将某一个元素增加或减少 \(d\),求是所有元素相等的最小操作次数,或者不存在这样的操作方案. 数据范围:\(1\ ...

  6. Docker容器自动更新

    前言: Watchtower 是一个可以实现自动化更新 Docker 基础镜像与容器的实用工具.它监视正在运行的容器以及相关的镜像,当检测到reg­istry中的镜像与本地的镜像有差异时,它会拉取最新 ...

  7. 选课系统V1.0

    tree . . ├── bin │   ├── __init__.py │   └── start.py #启动文件 ├── conf │   ├── __init__.py │   └── set ...

  8. Linux(debian7)操作基础(四)之CPU频率调整 Linux系统CPU频率调整工具使用

    在Linux中,内核的开发者定义了一套框架模型来完成CPU频率动态调整这一目的,它就是CPU Freq系统.如下为CPU的几种模式(governor参数): ondemand:系统默认的超频模式,按需 ...

  9. org.apache.jasper.runtime.ELContextImpl cannot be cast to org.apache.jasper.el.ELContextImpl

    org.apache.jasper.runtime.ELContextImpl cannot be cast to org.apache.jasper.el.ELContextImpl错误怎么解决: ...

  10. ajax 有终止请求 abort 那 axios 有没有,怎么实现

    见代码 class View extends Component { constructor(props){ super(props); this.state = { cancel:null, can ...