当编写验证客户端提交的多个Form表单时,视图函数中的代码很快将变得冗长和难以阅读,调试和维护也变得难以忍受。通过使用WTForms库,将表单定义为继承于Form的类,使用该类可以验证所有表单,并且可以在模板中自动生成表单对应的HTML元素,定制HTML生成过程,从而实现业务逻辑代码和展示的分离,并使得代码简洁干净、易于维护。
1. 下载安装
安装WTForms
Shell
$ pip install WTForms
1
$pipinstallWTForms
2. 关键概念
Forms是WTForms库的核心容器,它包含一系列的Fields,可通过属性或字典样式访问;
Fields是最主要的表单处理单元,每一种表单数据类型对应着一种Field,Filed还包含一些有用的属性,如:标签、描述信息、验证错误信息等;
每一个Field都有一个Widget实例,用于生成该Field的HTML元素;
Field还包含一个Validators列表,用于指定该字段的验证规则。
3. 使用示例
创建一个表单:
创建表单示例
Python
from wtforms import Form, BooleanField, StringField, validators
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
accept_rules = BooleanField('I accept the site rules', [validators.InputRequired()])
1
2
3
4
5
6
fromwtformsimportForm,BooleanField,StringField,validators
classRegistrationForm(Form):
username=StringField('Username',[validators.Length(min=4,max=25)])
email=StringField('Email Address',[validators.Length(min=6,max=35)])
accept_rules=BooleanField('I accept the site rules',[validators.InputRequired()])
使用继承扩展表单项:
扩展表单项示例
Python
class ProfileForm(Form):
birthday = DateTimeField('Your Birthday', format='%m/%d/%y')
signature = TextAreaField('Forum Signature')
class AdminProfileForm(ProfileForm):
username = StringField('Username', [validators.Length(max=40)])
level = IntegerField('User Level', [validators.NumberRange(min=0, max=10)])
1
2
3
4
5
6
7
classProfileForm(Form):
birthday=DateTimeField('Your Birthday',format='%m/%d/%y')
signature=TextAreaField('Forum Signature')
classAdminProfileForm(ProfileForm):
username=StringField('Username',[validators.Length(max=40)])
level=IntegerField('User Level',[validators.NumberRange(min=0,max=10)])
在视图函数中使用表单:
使用表单示例
Python
@app.route("/register")
def register(request):
# 1. 创建表单实例
form = RegistrationForm(request.POST)
# 2. 当用户提交表单时,验证表单
if request.method == 'POST' and form.validate():
user = User()
# 3. 表单验证通过后,执行正常的处理逻辑
user.username = form.username.data
user.email = form.email.data
user.save()
redirect('register')
return render_response('register.html', form=form)
1
2
3
4
5
6
7
8
9
10
11
12
13
@app.route("/register")
defregister(request):
# 1. 创建表单实例
form=RegistrationForm(request.POST)
# 2. 当用户提交表单时,验证表单
ifrequest.method=='POST'andform.validate():
user=User()
# 3. 表单验证通过后,执行正常的处理逻辑
user.username=form.username.data
user.email=form.email.data
user.save()
redirect('register')
returnrender_response('register.html',form=form)
4. 常用Validators
validator定义
说明
DataRequired(message=None)
检查当前field是否有值,若无,则验证失败
Email(message=None)
检查当前field是否的值是否为email地址
EqualTo(fieldname, message=None)
比较当前field的值是否与fieldname对应field的值相同
InputRequired(message=None)
验证用户是否输入了内容
IPAddress(ipv4=True, ipv6=False, message=None)
验证是否为IP地址
Length(min=-1, max=-1, message=None)
验证输入的字符串长度是否在指定范围内
MacAddress(message=None)
验证是否为MAC地址
NumberRange(min=None, max=None, message=None)
验证数值是否在指定范围内
Optional(strip_whitespace=True)
指定当前field为可选,停止对其进行验证
Regexp(regex, flags=0, message=None)
使用正则表达式验证当前field
URL(require_tld=True, message=None)
验证是否为URL地址
UUID(message=None)
验证是否为UUID字符串
AnyOf(values, message=None, values_formatter=None)
验证输入值是否为values之一
NoneOf(values, message=None, values_formatter=None)
验证输入值是否不是values中任何一个
5. 自定义validators
自定义validator示例
Python
# 1. 定义自定义validator
class Length(object):
# 2. 定义validator初始化输入
def __init__(self, min=-1, max=-1, message=None):
self.min = min
self.max = max
if not message:
message = u'Field must be between %i and %i characters long.' % (min, max)
self.message = message
# 3. 定义验证时的调用接口
def __call__(self, form, field):
l = field.data and len(field.data) or 0
if l < self.min or self.max != -1 and l > self.max:
raise ValidationError(self.message)
class MyForm(Form):
name = StringField('Name', [InputRequired(), Length(max=50)]) # 4. 使用自定义validator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1. 定义自定义validator
classLength(object):
# 2. 定义validator初始化输入
def__init__(self,min=-1,max=-1,message=None):
self.min=min
self.max=max
ifnotmessage:
message=u'Field must be between %i and %i characters long.'%(min,max)
self.message=message
# 3. 定义验证时的调用接口
def__call__(self,form,field):
l=field.dataandlen(field.data)or0
iflself.max:
raiseValidationError(self.message)
classMyForm(Form):
name=StringField('Name',[InputRequired(),Length(max=50)])# 4. 使用自定义validator
6. 渲染Fields
可在网页模板中使用fields对象,调用其预定义函数,输出对应的html标签,使用示例如下:
表单定义
Python
class LoginForm(Form):
username = StringField('Username')
password = PasswordField('Password')
form = LoginForm()
1
2
3
4
5
classLoginForm(Form):
username=StringField('Username')
password=PasswordField('Password')
form=LoginForm()
表单输出模板
Python
1
2
3
4
最终的HTML输出
XHTML
Username:
Password:
1
2
3
4
5
6
7
8
9
10
Username:
Password:
对于验证时的错误信息,可以在模板中使用如下方法输出:
XHTML
{% if form.errors %}
{% for field_name, field_errors in form.errors|dictsort if field_errors %}
{% for error in field_errors %}
{{ form[field_name].label }}: {{ error }}{% endfor %}
{% endfor %}
{% endif %}
1
2
3
4
5
6
7
8
9
{%ifform.errors%}
{% for field_name, field_errors in form.errors|dictsort if field_errors %}
{% for error in field_errors %}
{{ form[field_name].label }}: {{ error }}{% endfor %}
{% endfor %}
{%endif%}