hzyuhz 2020-06-28
在web程序中,表单是与用户交互的最常见的方式之一。用户注册、登录、撰写文章。不过,表单的处理却并不简单。你不仅要创建表单,验证用户输入的内容,向用户显示错误提示,还要获取并保存数据。幸运的是,强大的WTForms可以帮我们解决这些问题。WTForms是一个使用Python编写的表单库,它使得表单的定义、验证(服务器端)和处理变得非常轻松。这一章我们会介绍在Web程序中处理表单的方法和技巧。
<form method="post"> # 表单 <label for="username">Username</label><br> <input type="text" name="username" placeholder="Héctor Rivera"><br> # 输入字段 <label for="password">Password</label><br> <input type="password" name="password" placeholder="19001130"><br> <input id="remember" name="remember" type="checkbox" checked> <label for="remember"><small>Remember me</small></label><br> <input type="submit" name="submit" value="Log in"> # 提交 </form>
<label>
标签则用来定义字段的标签文字。我们可以在<form>
和<input>
标签中使用各种属性来对表单进行设置。上面的表单被浏览器解析后会生成两个输入框,一个勾选框和一个提交按钮。
WTForms支持在Python中使用类定义表单,然后直接通过类定义生成对应的HTML代码,这种方式更加方便,而且使表单更易于重用。因此,除非是非常简单的程序,或者是你想让表单的定义更加灵活,否则我们一般不会在模板中直接使用HTML编写表单,
扩展Flask-WTF集成了WTForms,使用它可以在Flask中更方便地使用WTFroms。Flask-WTF将表单数据解析、CSRF保护、文件上传等功能与Flask集成,另外还附加reCAPTCHA支持(google验证码服务)。
Flask-WTF默认为每个表单启用CSRF保护,它会为我们自动生成和验证CSRF令牌。默认情况下,Flask-WTF使用程序密钥来对CSRF令牌进行签名,所以我们需要为程序设置密钥:app.secret_key=‘secret string‘
表单由Python类表示,这个类继承从WTForms导入的Form基类。from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
。字段分别用表单类的类属性来表示。
随意定一个类:
class LoginForm(Form): ... username = StringField(‘Username‘, validators=[DataRequired()]) ... password = PasswordField(‘Password‘, validators=[DataRequired(), Length(8, 128)]) ... remember = BooleanField(‘Remember me‘) ... submit = SubmitField(‘Log in‘)
这里的LoginForm表单类中定义了四个字段:文本字段StringField、密码字段Password Field、勾选框字段BooleanField和提交按钮字段SubmitField。字段类从wtforms包导入。
常用字段:
通过实例化字段类时传入的参数,我们可以对字段进行设置,字段类构造方法接收的常用参数:
WTForms中,验证器(validator)是一系列用于验证字段数据的类,我们在实例化字段类时使用validators关键字来指定附加的验证器列表。验证器从wtforms.validators模块中导入,常用的验证器:
类定义的表单如何输出HTML代码的。
>>> form = LoginForm() >>> form.username() u‘<input id="username" name="username" type="text" value="">‘ >>> form.submit() u‘<input id="submit" name="submit" type="submit" value="Submit">‘
>>> form.username.label() u‘<label for="username">Username</label>‘ >>> form.submit.label() u‘<label for="submit">Submit</label>‘
使用render_temple()
函数中使用关键字参数form将表单实例传入模板。
from forms import LoginForm @app.route(‘/basic‘) def basic(): form = LoginForm() return render_template(‘basic.html‘, form=form)
在模板中,只需要调用表单类的属性即可获取字段对应的HTML代码,如果需要传入参数,也可以添加括号,如:
<form method="post"> {{ form.csrf_token }} <!-- 渲染CSRF令牌隐藏字段 --> {{ form.username.label }}<br>{{ form.username }}<br> {{ form.password.label }}<br>{{ form.password }}<br> {{ form.remember }}{{ form.remember.label }}<br> {{ form.submit }}<br> </form>
form.csrf_token字段包含了自动生成的CSRF令牌值,在提交表单后会自动被验证,为了确保表单通过验证,我们必须在表单中手动渲染这个字段(Flask-WTF为表单类实例提供了一个form.hidden_tag()方法,这个方法会依次渲染表单中所有的隐藏字段。因为csrf_token字段也是隐藏字段,所以当这个方法被调用时也会渲染csrf_token字段。
渲染后实际效果:
<form method="post"> <input id="csrf_token" name="csrf_token" type="hidden" value="IjVmMDE1ZmFjM2VjYmZjY...i.DY1QSg.IWc1WEWxr3TvmAWCTHRMGjIcDOQ"> <label for="username">Username</label><br> <input id="username" name="username" type="text" value=""><br> <label for="password">Password</label><br> <input id="password" name="password" type="password" value=""><br> <input id="remember" name="remember" type="checkbox" value="y"><label for="remember">Remember me</label><br> <input id="submit" name="submit" type="submit" value="Log in"><br> </form>
表单数据的处理涉及很多内容,除去表单提交不说,从获取数据到保存数据大致会经历以下步骤:
1)解析请求,获取表单数据。
2)对数据进行必要的转换,比如将勾选框的值转换成Python的布尔值。
3)验证数据是否符合要求,同时验证CSRF令牌。
4)如果验证未通过则需要生成错误消息,并在模板中显示错误消息。
5)如果通过验证,就把数据保存到数据库或做进一步处理。
除非是简单的程序,否则手动处理不太现实,使用Flask-WTF和WTForms可以极大地简化这些步骤。
提交表单时,就会创建一个表单的HTTP请求,请求中包含表单各个字段的数据。表单的提交行为主要由三个属性控制: