安装:pip install flask-wtf
flask_wtf是一个关于表单的扩展库,默认情况下, Flask-WTF 能保护所有表单免受跨站请求伪造( Cross-Site Request Forgery,CSRF)的攻击。恶意网站把请求发送到被攻击者已登录的其他网站时就会引发 CSRF 攻击。为了实现 CSRF 保护,FlaskWTF 需要程序设置一个密钥。 Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪 。
#设置秘钥的方式:
app.config['SECRET_KEY'] = '随便什么字符串'
使用flask_wtf时,每个表单都抽象成一个类,这个类继承自FlaskForm类,这个类定义了各种表单中的字段,每个字段都用对象表示。并且flask_wtf中还定义了各种验证函数,用来验证用户提交的输入值是否符合要求。
#首先构造一个html的原生表单
#用flask_wtf构造一个同样的表单类:
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField #表单中的字段
from wtforms.validators import DataRequired, ValidationError #验证方法
class NameForm(FlaskForm):
class NameForm(FlaskForm):
name = StringField('用户名', validators=[DataRequired()])
submit = SubmitField('提交')
这个表单中的字段都定义为类变量,类变量的值是相应字段类型的对象。在这个示例中,NameForm 表单中有一个名为 name 的文本字段和一个名为 submit 的提交按钮。 StringField类表示属性为 type="text"
的 元素。 SubmitField 类表示属性为
type="submit"
的 元素。字段构造函数的第一个参数是把表单渲染成 HTML 时使用的标号。StringField 构造函数中的可参数 validators 指定一个由验证函数组成的列表,在接受用户提交的数据之前验证数据。验证函数 Required() 确保提交的字段不为空。
字段类型 | 说 明 |
---|---|
StringField | 文本字段 |
TextAreaField | 多行文本字段 |
PasswordField | 密码文本字段 |
HiddenField | 隐藏文本字段 |
DateField | 文本字段,值为 datetime.date 格式 |
DateTimeField | 文本字段,值为 datetime.datetime 格式 |
IntegerField | 文本字段,值为整数 |
DecimalField | 文本字段,值为 decimal.Decimal |
FloatField | 文本字段,值为浮点数 |
BooleanField | 复选框,值为 True 和 False |
RadioField | 一组单选框 |
SelectField | 下拉列表 |
SelectMultipleField | 下拉列表,可选择多个值 |
SubmitField | 表单提交按钮 |
FileField | 文件上传字段 |
FormField | 把表单作为字段嵌入另一个表单 |
FieldList | 一组指定类型的字段 |
+ WTForms 内建的验证函数
表4-2
验证函数 | 说 明 |
---|---|
验证电子邮件地址 | |
EqualTo | 比较两个字段的值;常用于要求输入两次密码进行确认的情况 |
IPAddress | 验证 IPv4 网络地址 |
Length | 验证输入字符串的长度 |
NumberRange | 验证输入的值在数字范围内 |
Optional | 无输入值时跳过其他验证函数 |
Required | 确保字段中有数据 |
Regexp | 使用正则表达式验证输入值 |
URL | 验证 URL |
AnyOf | 确保输入值在可选值列表中 |
NoneOf | 确保输入值不在可选值列表中 |
在视图函数汇中实例一个表单类,然后把实例对象作为参数传入HTML就行渲染就可以变成HTML的表单
#假设是实例了一个名为form的实例
{#原生渲染#}
表单校验
@app.route('/', methods=['GET', 'POST'])
def index():
# 创建表单对象
form = NameForm()
name = None
# 表单校验
if form.validate_on_submit():
name = form.name.data
form.name.data = ''
# 渲染时分配到模板文件
return render_template('form.html', form=form, name=name)
POST重定向GET
@app.route('/', methods=['GET', 'POST'])
def index():
# 创建表单对象
form = NameForm()
# 表单校验
if form.validate_on_submit():
session['name'] = form.name.data
return redirect(url_for('index'))
name = session.get('name')
# 渲染时分配到模板文件
return render_template('form.html', form=form, name=name)
### 自定义字段验证:
就是写一个’validate_字段’的函数,如下:
class NameForm(FlaskForm):
name = StringField('用户名', validators=[DataRequired()])
submit = SubmitField('提交')
# 自定义字段验证
def validate_name(self, field):
if len(field.data) < 6:
raise ValidationError('用户名长度不能少于6个字符')
说明:
当用户发出请求后,有时状态发生了改变,需要给与提示、警告等信息时,通过可以弹出警告框,然后用户可以手动取消掉。
使用:
在合适的时候书写flash消息,使用flash函数
@app.route('/', methods=['GET', 'POST'])
def index():
# 创建表单对象
form = NameForm()
# 表单校验
if form.validate_on_submit():
last_name = session.get('name')
# 原来有,并且与现在的不一样,给出提示消息
if last_name and last_name != form.name.data:
flash('用户名已经改变')
session['name'] = form.name.data
return redirect(url_for('index'))
name = session.get('name')
# 渲染时分配到模板文件
return render_template('form.html', form=form, name=name)
在这个示例中,每次提交的名字都会和存储在用户会话中的名字进行比较,而会话中存储
的名字是前一次在这个表单中提交的数据。如果两个名字不一样,就会调用 flash() 函数,
在发给客户端的下一个响应中显示一个消息。仅调用 flash() 函数并不能把消息显示出来,程序使用的模板要渲染这些消息。最好在模板中渲染 Flash 消息,因为这样所有页面都能使用这些消息。
Flask 把 get_flashed_messages() 函数开放给模板,用来获取并渲染消息。
如下:
{% for message in get_flashed_messages() %}
<div class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert"
aria-label="Close"><span
aria-hidden="true">×span>button>
{{ message }}
div>
{% endfor %}
说明:这个扩展是一个时间本地化显示的库,依赖于Jquery。
安装:pip install flask-moment
使用:
from flask_moment import Moment
moment = Moment(app)
模板使用
{% extends 'bootstrap/base.html' %}
{% block content %}
<div>时间日期:{{ moment(current_time).format('L') }}div>
<div>私人定制:{{ moment(current_time).format('YYYY-MM-DD') }}div>
<div>发表于:{{ moment(current_time).fromNow() }}div>
{% endblock %}
{% block scripts %}
{{ super() }}
{# 原则上需要导入jquery,bootstrap已经导入,可以省略 #}
{{ moment.include_jquery() }}
{# 加载moment.js #}
{{ moment.include_moment() }}
{# 显示中文,默认显示英文 #}
{{ moment.locale('zh-CN') }}
{% endblock %}