这篇文章作为上一篇的续篇,所以结构上也和上一篇一样。
使用Flask-WTF
这是一个登录的视图函数:
@auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
email = form.email.data
...
return render_template('login.html', form=form)
验证数据
当我们点击了表单上的提交按钮时,form.validate_on_submit()判断会做下面两件事情:
- 通过is_submitted()通过判断HTTP方法来确认是否提交了表单
- 通过WTForms提供的validate()来验证表单数据(使用我们在下面的表单类里给每个字段传入的验证函数)
这是我们的表单类:
class LoginForm(FlaskForm):
email = StringField(u'邮箱', validators=[
DataRequired(message= u'邮箱不能为空'), Length(1, 64),
Email(message= u'请输入有效的邮箱地址,比如:username@domain.com')])
password = PasswordField(u'密码',
validators=[Required(message= u'密码不能为空')])
submit = SubmitField(u'登录')
在Flask-WTF 0.13版本,引入的表单类为FlaskForm;
在WTForms 3.0版本,验证函数Required变为DataRequired。
当validate()验证未通过时,会在表单字段下面显示我们传进去的错误提示(例如message= u’邮箱不能为空’)。
自定义验证
你可以在表单类创建自定义的验证函数,一个简单的例子:
def validate_username(self, field):
if User.query.filter_by(username=field.data).first():
raise ValidationError(u'用户名已被注册,换一个吧。')
这个例子验证用户名是否已经存在(这里使用SQLAlchemy),其中field.data是数据。
ValidationError从wtforms导入,用来向用户显示错误信息,验证函数的名称由validate_fieldname组成。你也可以在这里对用户数据进行预处理:
def validate_website(self, field):
if field.data[:4] != "http":
field.data = "http://" + field.data
这个函数对用户输入的网址进行处理(字段名为website)。
你也可以在表单类外面定义一个通用的验证函数,然后传入字段的验证函数列表里,具体见WTForms文档:http://wtforms.readthedocs.io/en/latest/validators.html#custom-validators
获取数据
验证通过后,我们使用form.email.data来获得数据,WTForms提供的静态方法.data返回一个以字段名(field name)和字段值(field value)作为键值对的字典。
不使用Flask-WTF,只使用WTForms
我们既然已经知道了Flask-WTF的form.validate_on_submit()的工作原理,我们也可以自己实现:
@auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'POST' and form.validate():
email = form.email.data
...
return render_template('login.html', form=form)
但是这样要复杂一点,而且在渲染时比较繁琐,如果你想了解更多,可以参考:http://flask.pocoo.org/docs/0.11/patterns/wtforms/。
不使用Flask-WTF,也不使用WTForms
在一些特殊场景下,比如一个特别简单的表单。这是上一个实践项目的表单:
<form method="POST" action="{{ url_for('custom') }}">
<input type="text" name="time" class="time-input" placeholder="example: 12/30s/20m/2h">
<input type="submit" class="startButton" value="START">
</form>
这时要给表单添加一个action属性,属性值填写要处理表单数据的视图函数。这是处理表单数据的函数:
@app.route('/custom', methods=['GET', 'POST'])
def custom():
if request.method == 'POST':
time = request.form.get('time', 180)
...
获取数据
使用request来获取数据(request从flask导入),使用字段的name值来区分,你可以用:
request.form['input-name']
或是:
request.form.get('input-name', default_value)
注意如果你使用第一种方式获取数据,要确保有数据才行,像勾选框这样可以留空的字段,如果用户没有填写数据,提交后会引起HTTP 400错误,这时应该使用第二种方式来设置一个默认值。
你也可以像使用Flask-WTF一样为表单填入已经存储在数据库里的内容,不过要自己填到表单里:
@app.route('/custom', methods=['GET', 'POST'])
def custom():
if request.method == 'POST':
time = request.form.get('time', 180)
...
email = 'example@flask.com'
return render_template('demo.html', email=email)
在HTML里,将email作为value的值:
<input name="email" value="{{ email }}">
验证数据
因为没有使用WTForms,所以验证数据要自己实现,常见的验证通过你的Python知识大多都很容易实现,错误信息则可以使用flash()传递。
大多数新手对正则表达式比较头疼,在这里推荐一个在线正则表达式编辑网站,regex101.com,支持PHP、PCRE、Python、Golang和 JavaScript,可以写测试,查cheatsheet,生成代码,解释表达式,非常好用!
实践:多个表单字段的生成及数据的获取
其实这是后面豆瓣相册实践项目里的内容,就提前透露一点吧。在豆瓣相册里,有一个批量修改的功能,在这个页面,要为你的相册里的每一张图片生成一个编辑框。我们可以直接使用for循环在HTML里生成表单。
生成表单
用for循环生成input,注意我用每个图片的id作为相应输入框的name值:
<form action="{{ url_for('.edit_photos', id=album.id) }}" method="POST">
<ul>
{% for photo in photos %}
<li>
<img class="img-responsive portrait" src="{{ photo.path }}" alt="Some description"/>
<textarea name="{{ photo.id }}" placeholder="add some description" rows="3">{% if photo.description %}{{ photo.description }}{% endif %}</textarea>
</li>
{% endfor %}
</ul>
<hr>
<input class="btn btn-success" type="submit" name="submit" value="submit">
获取数据
然后我在视图函数同样用for循环迭代所有图片,然后使用request获取相应的数据(通过图片的id作为name值获取)然后保存到数据库:
@app.route('/edit-photos/<int:id>', methods=['GET', 'POST'])
@login_required
def edit_photos(id):
album = Album.query.get_or_404(id)
photos = album.photos.order_by(Photo.order.asc())
if request.method == 'POST':
for photo in photos:
photo.about = request.form[str(photo.id)]
db.session.add(photo)
return redirect(url_for('.album', id=id))
return render_template('edit_photo.html', album=album, photos=photos)
就先简单讲一下,具体内容等到后面再讲。
相关链接
- Flask-WTF文档:Flask-WTF – Flask-WTF 0.13
- WTForms文档:WTForms Documentation
- Flask文档WTForms章节:http://flask.pocoo.org/docs/0.11/patterns/wtforms/
- Flask snippet Form分类:Flask (A Python Microframework)
– – – – –
更多关于Flask的优质内容,欢迎关注Hello, Flask! – 知乎专栏。
为什么我这边验证其只能验证有没有字符,长度和email啥的都验证不了
代码贴上来看看?