当编写验证客户端提交的多个Form表单时,视图函数中的代码很快将变得冗长和难以阅读,调试和维护也变得难以忍受。通过使用WTForms库,将表单定义为继承于Form的类,使用该类可以验证所有表单,并且可以在模板中自动生成表单对应的HTML元素,定制HTML生成过程,从而实现业务逻辑代码和展示的分离,并使得代码简洁干净、易于维护。
1. 下载安装
1 |
$ pip install WTForms |
2. 关键概念
- Forms是WTForms库的核心容器,它包含一系列的Fields,可通过属性或字典样式访问;
- Fields是最主要的表单处理单元,每一种表单数据类型对应着一种Field,Filed还包含一些有用的属性,如:<label>标签、描述信息、验证错误信息等;
- 每一个Field都有一个Widget实例,用于生成该Field的HTML元素;
- Field还包含一个Validators列表,用于指定该字段的验证规则。
3. 使用示例
创建一个表单:
1 2 3 4 5 6 |
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 7 |
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 8 9 10 11 12 13 |
@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) |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 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 |
6. 渲染Fields
可在网页模板中使用fields对象,调用其预定义函数,输出对应的html标签,使用示例如下:
1 2 3 4 5 |
class LoginForm(Form): username = StringField('Username') password = PasswordField('Password') form = LoginForm() |
1 2 3 4 |
<form method="POST" action="/login"> <div>{{ form.username.label }}: {{ form.username(class="css_class") }}</div> <div>{{ form.password.label }}: {{ form.password() }}</div> </form> |
1 2 3 4 5 6 7 8 9 10 |
<form method="POST" action="/login"> <div> <label for="username">Username</label>: <input class="css_class" id="username" name="username" type="text" value="" /> </div> <div> <label for="password">Password</label>: <input id="password" name="password" type="password" value="" /> </div> </form> |
对于验证时的错误信息,可以在模板中使用如下方法输出:
1 2 3 4 5 6 7 8 9 |
{% if form.errors %} <ul class="errors"> {% for field_name, field_errors in form.errors|dictsort if field_errors %} {% for error in field_errors %} <li>{{ form[field_name].label }}: {{ error }}</li> {% endfor %} {% endfor %} </ul> {% endif %} |