Flask表单验证
- 表单设计
创建form标签,设置action为url_for('register'),method为POST。表示将register视图函数反转为URL,在之后单击‘提交’按钮时,会把所有form标签下输入框中的内容都提交给这个URL,并且会以POST方式提交。在form标签下,最后添加了一个type为‘submit’的input标签,被渲染出来是一个按钮。
- 表单类编写
注册页面表单设计好后,需要对字段有一定要求,比如用户名长度、邮箱格式、密码是否一致...因此这里通过抓包形式获取注册时的请求数据。在forms.py文件下进行表单类编写。
from wtforms import Form, StringField, ValidationError
from wtforms.validators import length, email, equal_to
class RegisterForm(Form):
username = StringField(validators=[length(min=3, max=20, message='请输入正确长度的用户名!')])
email = StringField(validators=[email(message='请输入正确格式的邮箱!')])
password = StringField(validators=[length(min=6, max=20, message='请输入正确长度的密码!')])
confirm_password = StringField(validators=[equal_to('password', message='两次密码不一致!')])
从wtforms中导入Form基类,所有表单类都必须继承自Form基类,字段名称必须和相对应的HTML文件中表单元素的name一致。因为当前这4个字段属性都是字符串类型,所以用StringField,其他还有IntegerField等等。validators为验证器集合,可以存放多个验证器,不满足要求会提示错误信息,错误信息即为message中内容。
- 视图函数中使用表单
@app.route('/register', methods=['GET','POST'])
def register():
if request.method == 'GET':
return render_template('register.html')
else:
form = RegisterForm(request.form)
if form.validate():
email = form.email.data
username = form.username.data
password = form.password.data
print('email:', email)
print('username:', username)
print('password:', password)
return '注册成功!'
else:
for errors in form.errors.values():
for error in errors:
flash(error)
return redirect(url_for('register'))
首先用RegisterForm类创建一个form对象,request.form是一个类字典类型,保存了从浏览器中提交上来的表单数据,调用form.validate()方法判断RegisterForm中定义的所有字段是否验证通过,全部通过验证则通过 form.<字段名>.data 获取对应字段数据(这里不从request.form获取数据,因为reques.form是服务器获取到的从浏览器提交的数据,都是字符串类型,而通过form对象获取到的数据会经过处理,保留数据类型)。
获取到所有数据后,就可以把数据存储到数据库中或进行其他操作。
若验证失败,通过form.errors.values()获取所有错误内容即之前的message信息,并存储到flash中,form.errors是字典类型,加了values后是列表。在模板中把flash消息显示出来。
<ul>
{% for message in get_flashed_messages() %}
<li>{{ message }}</li>
{% endfor %}
</ul>
使用flash消息,需先配置SECRET_KEY,密钥内容可以随意字符
app.config['SECRET_KEY'] = 'AASDAD'
redirect为重定向函数,输入一个URL后,自动跳转到另一个URL所在的地址
- 自定义验证字段
自定义验证逻辑,比如已经注册过的邮箱不能再次注册,这时需要查询数据,判断邮箱是否存在。自定义某个字段的验证逻辑可以通过在表单类中自定义方法 validate_<字段名> 来实现。
class RegisterForm(Form):
username = StringField(validators=[length(min=3, max=20, message='请输入正确长度的用户名!')])
email = StringField(validators=[email(message='请输入正确格式的邮箱!')])
password = StringField(validators=[length(min=6, max=20, message='请输入正确长度的密码!')])
confirm_password = StringField(validators=[equal_to('password', message='两次密码不一致!')])
def validate_email(self, field):
email = field.data
if email in register_email:
raise ValidationError('邮箱已经被注册!')
return True
register_email变量可在之前进行定义,表示数据库中已经被注册的邮箱。之后在视图函数中调用form.validate()方法时,RegisterForm底层会自动调用validate_email方法,并传递一个field参数,验证的是哪个字段,field就代表相应字段。通过field.data拿到对应值。若验证失败,抛出wtforms.ValidationError异常,并指定一个错误消息,该错误消息会出现在form.errors中。