模板基本语法
{% if user %} {{ user }} {% else %} hello! <ul> {% for index in indexs %} <li> {{ index }} li> {% endfor %} ul>
一 变量
在模板中{{ variable }}结构表示变量,是一种特殊的占位符,告诉模板引擎这个位置的值,从渲染模板时使用的数据中获取;Jinja2除了能识别基本类型的变量,还能识别{};
视图:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/index")
def index():
data = {
"name": "test",
"size": 11,
"adict": {"title": "index"},
"alist": [1,2,3,4,5,6]
}
return render_template('index.html', **data)
# return render_template("index.html", name="tile")
if __name__ == '__main__':
app.run()
模板:
DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<meta http-equiv='Content-type' content='text/htm'>
head>
<body>
<p>name---{{ name }}p>
<p>size---{{ size }}p>
<p>adict---title:{{ adict["title"] }}p>
<p>adict---title:{{ adict.title }}p>
<p>alist---{{ alist }}p>
<p>alist---:alist[0]:{{ alist[0] }}p>
<p>alist---:alist[2]:{{ alist.2 }}p>
<p>alist---:alist[0]+alist[1]:{{ alist[0] + alist[1] }}p>
<p>{{ "hello" + "flask" }}p>
body>
html>
自定义错误页面:
@app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404
二 过滤器
过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,这就用到了过滤器。 过滤器的使用方式为:变量名 | 过滤器。 过滤器名写在变量名后面,中间用 | 分隔。如:{{variable | capitalize}},这个过滤器的作用:把变量variable的值的首字母转换为大写,其他字母转换为小写。 其他常用过滤器如下:
2.1 字符串过滤器:
safe:禁用转义;
<p>{{ '<em>helloem>' | safe }}p>
capitalize:把变量值的首字母转成大写,其余字母转小写;
<p>{{ 'hello' | capitalize }}p>
lower:把值转成小写;
<p>{{ 'HELLO' | lower }}p>
upper:把值转成大写;
<p>{{ 'hello' | upper }}p>
title:把值中的每个单词的首字母都转成大写;
<p>{{ 'hello' | title }}p>
trim:把值的首尾空格去掉;
<p>{{ ' hello world ' | trim }}p>
reverse:字符串反转;
<p>{{ 'olleh' | reverse }}p>
format:格式化输出;
<p>{{ '%s is %d' | format('name',17) }}p>
striptags:渲染之前把值中所有的HTML标签都删掉;
<p>{{ '<em>helloem>' | striptags }}p>
2.2 支持链式使用过滤器
<p>{{ “ hello world “ | trim | upper }}p>
2.3 列表过滤器
first:取第一个元素 <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>
2.4 语句块过滤
{% filter upper %}
this is a Flask Jinja2 introduction
{% endfilter %}
2.5 自定义过滤器:
过滤器的本质是函数。当模板内置的过滤器不能满足需求,可以自定义过滤器。自定义过滤器有两种实现方式:一种是通过Flask应用对象的add_template_filter方法。还可以通过装饰器来实现自定义过滤器。
自定义的过滤器名称如果和内置的过滤器重名,会覆盖内置的过滤器。
实现方式一:通过调用应用程序实例的add_template_filter方法实现自定义过滤器。该方法第一个参数是函数名,第二个参数是自定义的过滤器名称。
def list_step_2(li):
"""自定义过滤器"""
return li[::2]
# 注册过滤器
app.add_template_filter(list_step_2, "li2")
实现方式二:用装饰器来实现自定义过滤器。装饰器传入的参数是自定义的过滤器名称。
@app.template_filter("li3")
def list_step_3(li):
"""自定义过滤器"""
return li[::3]
三 Web表单:
web表单是web应用程序的基本功能。
它是HTML页面中负责数据采集的部件。表单有三个部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。
在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且它有验证表单数据的功能。
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 | 验证输入值不在可选列表中 |
使用Flask-WTF需要配置参数SECRET_KEY。
CSRF_ENABLED是为了CSRF(跨站请求伪造)保护。 SECRET_KEY用来生成加密令牌,当CSRF激活的时候,该设置会根据设置的密匙生成加密令牌。
在HTML页面中直接写form表单:
#模板文件 <form method='post'> <input type="text" name="username" placeholder='Username'> <input type="password" name="password" placeholder='password'> <input type="submit"> form>
视图函数中获取表单数据:
from flask import Flask,render_template,request
@app.route('/login',methods=['GET','POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
print username,password
return render_template('login.html',method=request.method)
使用Flask-WTF实现表单。
pip install Flask-WTF
配置参数:
app.config['SECRET_KEY'] = '.........'
模板页面:
"zh-CN"> "UTF-8">Title 'Content-type' content='text/htm'>
视图函数:
from flask import Flask, render_template, url_for, redirect, session from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, EqualTo app = Flask(__name__) app.config["SECRET_KEY"] = "ada898u2q11joloadad02" class RegiterForm(FlaskForm): username = StringField(label="用户名", validators=[DataRequired("用户名不能为空")]) password = PasswordField(label="密码", validators=[DataRequired("密码不能为空")]) repassword = PasswordField(label="确认密码", validators=[DataRequired("确认密码不能为空"), EqualTo("password", "两次密码输入不一致")]) submit = SubmitField(label="提交") @app.route("/register", methods=['GET', "POST"]) def register(): # 创建表单对象, 如果是post请求, 前端发送了数据,flask会把数据在构造form对象的数据,存在对象中 reg_form = RegiterForm() # 判断form中的数据是否合法 if reg_form.validate_on_submit(): username = reg_form.username.data password = reg_form.password.data repassword = reg_form.repassword.data session["username"] = username print(username, password, repassword) return redirect(url_for("index")) return render_template('register.html', reg_form=reg_form) @app.route("/index") def index(): username = session.get("username") return "hello %s " % username if __name__ == '__main__': app.run()
四 控制语句
4.1 if控制语句
@app.route('/user') def user(): user = 'wusong' return render_template('user.html',user=user)
{% if user %}hello {{user}} {% else %}welcome to flask {% endif %}hello world
4.2 for循环语句
@app.route('/loop') def loop(): fruit = ['apple','orange','pear','grape'] return render_template('loop.html',fruit=fruit)
{% if user %}hello {{user}} {% else %}welcome to flask {% endif %}hello world
-
{% for index in fruit %}
- {{ index }} {% endfor %}
五 宏、继承、包含
类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余。
Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复。
5.1 宏
定义宏
{% macro input() %} "text" name="username" value=""> {% endmacro %}
调用宏
{{ input() }}
定义带参数的宏
{% macro input1(name, value="", type="text") %} "{{ type }}" name="{{ name }}" value="{{ value }}"> {% endmacro %}
调用宏,并传递参数
{{ input1(pwd, type="password") }}
把宏单独抽取出来,封装成html文件,其它模板中导入使用
文件名可以自定义macro_input.html
{% macro function() %} "text" name="username" placeholde="Username"> "password" name="password" placeholde="Password"> "submit"> {% endmacro %}
在其它模板文件中先导入,再调用
{% import 'macro_input.html' as func %} {{ func.function() }}
5.2模板继承
模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。
{% block top %}.......{% endblock %}标签定义的内容,相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。
父模板: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 %}
- 宏、继承、包含:
-
宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。
-
继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。
-
宏(Macro)的功能类似函数,可以传入参数,需要定义、调用。
-
包含(include)是直接将目标模板文件整个渲染出来。
-
六 Flask中的特殊变量和方法
在Flask中,有一些特殊的变量和方法是可以在模板文件中直接访问的。
config 对象:
config 对象就是Flask的config对象,也就是 app.config 对象。
{{ config.SQLALCHEMY_DATABASE_URI }}
request 对象:
就是 Flask 中表示当前请求的 request 对象,request对象中保存了一次HTTP请求的一切信息。
request常用的属性如下:
属性 | 说明 | 类型 |
---|---|---|
data | 记录请求的数据,并转换为字符串 | * |
form | 记录请求中的表单数据 | MultiDict |
args | 记录请求中的查询参数 | MultiDict |
cookies | 记录请求中的cookie信息 | Dict |
headers | 记录请求中的报文头 | EnvironHeaders |
method | 记录请求使用的HTTP方法 | GET/POST |
url | 记录请求的URL地址 | string |
files | 记录请求上传的文件 | * |
{{ request.url }}
url_for 方法:
url_for() 会返回传入的路由函数对应的URL,所谓路由函数就是被 app.route() 路由装饰器装饰的函数。如果我们定义的路由函数是带有参数的,则可以将这些参数作为命名参数传入。
{{ url_for('index') }} {{ url_for('post', post_id=1024) }}
get_flashed_messages方法:
返回之前在Flask中通过 flash() 传入的信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages() 方法取出。
{% for message in get_flashed_messages() %} {{ message }} {% endfor %}
示例:
from flask import Flask, render_template, flash app = Flask(__name__) app.config["SECRET_KEY"] = "diaj29u912kjwsle01sda" flag = True @app.route("/index") def index(): global flag if flag: flash("flash1") flash("flash2") flash("flash3") flag = False return render_template("index.html") if __name__ == '__main__': app.run()
"zh-CN"> "UTF-8">Title 'Content-type' content='text/htm'>闪现
{% for msg in get_flashed_messages() %} {{ msg }} {% endfor %}