涉及到的插件和包有Flask-WTF,WTForms。内容有表单的创建使用流程,一些最佳实践,还有在页面显示提示消息的简单方式,配合Flask内置的 flash()。
Flask的requset对象包含了client端发送过来的所有请求,在request.form中就有POST方法提交过来的表单数据。直接使用这些数据可以搞定表单的操作,不过不方便,于是有了Flask-WTF这个插件,它将WTForms这个包嵌入Flask里,简化Flask下的使用。pip安装会把插件的以来也安装进来:
pip install flask-wtf
1
pipinstallflask-wtf
WTForms应该也同时被安装了。
跨站请求伪造(Cross-Site Request Forgery,CSRF) 保护
CSRF的原理不具体讲了,很简单,感兴趣直接网上搜即可。
Flask-WTF默认提供对CSRF的保护。应用里需要设置一个加密用的key,Flask-WTF利用这个key生成一个加密的记号来验证request带过来的表单数据。看看实例:
app = Flask(__name__)
app.config['SECRET_KEY'] = 'www.ttlsa.com'
1
2
app=Flask(__name__)
app.config['SECRET_KEY']='www.ttlsa.com'
app.config 是应用保存配置的一个字典。可以直接在字典里增加配置。SECRET_KEY这个配置变量被Flask和一些第三方插件使用,对不同的应用配置不同的值增加点可靠性。
另外,这个值最好放到环境变量里,直接写到代码里不太好。
表单类
使用Flask-WTF的时候,每一个表单都是类的形式,这个类需要继承自Form。这个类里定义一些代表表单各类域的对象,每个对象可以有多个验证器(validators)。验证器可以确保用户的输入是有效的。
原例子:
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required
class NameForm(Form):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
fromflask.ext.wtfimportForm
fromwtformsimportStringField,SubmitField
fromwtforms.validatorsimportRequired
classNameForm(Form):
name=StringField('What is your name?',validators=[Required()])
submit=SubmitField('Submit')
表单中的域在类中都定义成类变量。上例中,NameForm类里有文本域name和提交按钮submit两个。StringField代表有type="text"属性的元素。SubmitField代表有type="submit"属性的元素。构造器的第一个参数是后续渲染表单时候用到的标签(label)。
下例是一个带有文本域和提交按钮的表单例子:
from flask_wtf import Form
from wtforms import StringField, BooleanField, PasswordField,SubmitField
from wtforms.validators import DataRequired
class LoginForm(Form):
openid = StringField('openid', validators=[DataRequired()])
remember_me = BooleanField('remember_me', default = False)
password = PasswordField('password',validators=[DataRequired()])
submit = SubmitField('submit')
fromflask_wtfimportForm
fromwtformsimportStringField,BooleanField,PasswordField,SubmitField
fromwtforms.validatorsimportDataRequired
classLoginForm(Form):
openid=StringField('openid',validators=[DataRequired()])
remember_me=BooleanField('remember_me',default=False)
password=PasswordField('password',validators=[DataRequired()])
submit=SubmitField('submit')
表单中的域在类中都定义成类变量。上例中,LoginForm类里有字符串域openid,复选框remember_me, 密码域password,提交按钮submit。分别代表小面信息:
构造器的第一个参数是后续渲染表单时候用到的标签(label)。
在StringField里的validators参数定义了一些验证器,这些验证器会在用户提交数据前检查数据是否有效。Required验证器确保提交的内容不能为空。
WTForms提供的各种HTML域:
域类型 含义
StringField 文本
TextAreaField 多行文本
PasswordField 密码类文本
HiddenField 隐藏文本
DateField 接收给定格式的 datetime.datevalue 的文本
DateTimeField 接收给定格式的 datetime.datetimevalue 的文本T
IntegerField 接收整数的文本
DecimalField 接收decimal.Decimal类型值的文本
FloatField 接收浮点类型值的文本
BooleanField 选是否的复选框
RadioField 包含多个互斥选项的复选框
SelectField 下拉菜单
SelectMultipleField 可多选的下拉菜单
FileField 文件上传
SubmitField 提交
FormField 讲一个表单作为域放入另一个表单里
FieldList 一组给定类型的域
域类型含义
StringField文本
TextAreaField多行文本
PasswordField密码类文本
HiddenField隐藏文本
DateField接收给定格式的datetime.datevalue的文本
DateTimeField接收给定格式的datetime.datetimevalue的文本T
IntegerField接收整数的文本
DecimalField接收decimal.Decimal类型值的文本
FloatField接收浮点类型值的文本
BooleanField选是否的复选框
RadioField包含多个互斥选项的复选框
SelectField下拉菜单
SelectMultipleField可多选的下拉菜单
FileField文件上传
SubmitField提交
FormField讲一个表单作为域放入另一个表单里
FieldList一组给定类型的域
WTForms提供的各种验证器:
Validator Description
Email 邮箱格式
EqualTo 比较两个域的值,例如在要求输入两次密码的时候
IPAddress IPv4 地址
Length 按字符串的长度验证
NumberRange 输入数字需在某范围内
Optional 允许不填,不填的时候就忽略其他验证器
Required 必填
Regexp 通过一个正则表达式验证
URL URL格式
AnyOf 属于一组可能值中的一个
NoneOf 不属于一组可能值中的任何一个
ValidatorDescription
Email邮箱格式
EqualTo比较两个域的值,例如在要求输入两次密码的时候
IPAddressIPv4地址
Length按字符串的长度验证
NumberRange输入数字需在某范围内
Optional允许不填,不填的时候就忽略其他验证器
Required必填
Regexp通过一个正则表达式验证
URLURL格式
AnyOf属于一组可能值中的一个
NoneOf不属于一组可能值中的任何一个
渲染表单
表单的各类域在模板中渲染时表现为可调用的对象。假设将一个NameForm的实例name作为参数传入模板。
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }}
{{form.name.label}}{{form.name()}}
{{form.submit()}}
这样渲染出来的页面不美观,可以尝试改进下,在调用里传入一些参数,这些参数都会被转化为这个域的属性。然后你可以用CSS自己搞定美化问题:
{{ form.name.label }} {{ form.name(id='my-text-field') }}
{{ form.submit() }}
{{form.name.label}}{{form.name(id='my-text-field')}}
{{form.submit()}}
上述方式显然很累,之前加入了Bootstrap的支持,Flask-Bootstrap插件其实也对Flask-WTF创建的表单有高层接口的支持,可以用Bootstrap来修饰一下。然后表单的模板就可以简单写成:
{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
{%import"bootstrap/wtf.html"aswtf%}
{{wtf.quick_form(form)}}
从其他模板import个函数进来之前提到过,wtf.quick_form函数接受一个Flask-WTF的表单,然后用Bootstrap默认的样式渲染。
现在,首页index.html已经改为:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!
{{ wtf.quick_form(form) }}
{% endblock %}
{%extends"base.html"%}
{%import"bootstrap/wtf.html"aswtf%}
{%blocktitle%}Flasky{%endblock%}
{%blockpage_content%}
Hello,{%ifname%}{{name}}{%else%}Stranger{%endif%}!