<label>标签则用来定义字段的标签文字。我们可以在<form>和<input>标签中使用各种属性来对表单进行设置。上面的表单被浏览器解析后会生成两个输入框,一个勾选框和一个提交按钮。WTForms支持在Python中使用类定义表单,然后直接通过类定义生成对应的HTML代码,这种方式更加方便,而且使表单更易于重用。因此,除非是非常简单的程序,或者是你想让表单的定义更加灵活,否则我们一般不会在模板中直接使用HTML编写表单,
2 使用Flask-WTF处理表单扩展Flask-WTF集成了WTForms,使用它可以在Flask中更方便地使用WTFroms。Flask-WTF将表单数据解析、CSRF保护、文件上传等功能与Flask集成,另外还附加reCAPTCHA支持(google验证码服务)。Flask-WTF默认为每个表单启用CSRF保护,它会为我们自动生成和验证CSRF令牌。默认情况下,Flask-WTF使用程序密钥来对CSRF令牌进行签名,所以我们需要为程序设置密钥:app.secret_key='secret string'
2.1定义WTForms表单类表单由Python类表示,这个类继承从WTForms导入的Form基类。from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField。字段分别用表单类的类属性来表示。随意定一个类:
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模块中导入,常用的验证器:
2.2输出HTML代码类定义的表单如何输出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>'2.3在模板中渲染表单使用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>3表单处理表单数据的处理涉及很多内容,除去表单提交不说,从获取数据到保存数据大致会经历以下步骤:1)解析请求,获取表单数据。2)对数据进行必要的转换,比如将勾选框的值转换成Python的布尔值。3)验证数据是否符合要求,同时验证CSRF令牌。4)如果验证未通过则需要生成错误消息,并在模板中显示错误消息。5)如果通过验证,就把数据保存到数据库或做进一步处理。除非是简单的程序,否则手动处理不太现实,使用Flask-WTF和WTForms可以极大地简化这些步骤。
3.1提交表单提交表单时,就会创建一个表单的HTTP请求,请求中包含表单各个字段的数据。表单的提交行为主要由三个属性控制:
form标签的action属性用来指定表单被提交的目标URL,默认为当前URL,也就是渲染该模板的路由所在URL。如果你要把表单数据发送到其他URL,默认为当前URL,也就是渲染该模板的路由所在URL。如果你要把表单数据发送到其他URL,可以自定义这个属性值。当使用GET方法提交表单数据时,表单的数据会以查询字符串的形式附加在请求的URL里。http://localhost:5000/basic?username=greyli&password=12345
GET方式仅适用于长度不超过2000个字符,且不包含敏感信息的表单。因为这种方式会直接将用户提交的表单数据暴露在URL中,容易被攻击者截获,示例中的情况明显是危险的。因此,出于安全的考虑,我们一般使用POST方法提交表单。
3.2验证表单数据验证表单数据有两种方式:1.客户端验证HTML5验证属性、除了使用HTML5提供的属性实现基本的客户端验证,我们通常会使用JavaScript实现完善的验证机制。如果你不想手动编写JavaScript代码实现客户端验证,可以考虑使用各种JavaScript表单验证库,比如jQuery Validation Plugin(https://jqueryvalidation.org/)、Parsley.js(http://parsleyjs.org/)以及可与Bootstrap集成的Bootstrap Validator(http://1000hz.github.io/bootstrap-validator/,目前仅支持Bootstrap3版本)等。
2.服务器验证把用户输入的数据提交到服务器端,在服务器端对数据进行验证。Flask用WTForms验证机制:WTForms验证表单字段的方式是在实例化表单类时传入表单数据,然后对表单实例调用validate()方法。这会逐个对字段调用字段实例化时定义的验证器,返回表示验证结果的布尔值。如果验证失败,就把错误消息存储到表单实例的errors属性对应的字典中,验证的过程如下所示:
>>> from wtforms import Form, StringField, PasswordField, BooleanField >>> from wtforms.validators import DataRequired, Length >>> LoginForm(Form): ... username = StringField('Username', validators=[DataRequired()])... password = PasswordField('Password', validators=[DataRequired(), Length(8, 128)])>>> form = LoginForm(username='', password='123') >>> form.data # 表单数据字典{'username': '', 'password': '123'}>>> form.validate()False>>> form.errors # 错误消息字典{'username': [u'This field is required.'], 'password': [u'Field must be at least 8 characters long.']}>>> form2 = LoginForm(username='greyli', password='12345678') >>> form2.data{'username': 'greyli', 'password': '12345678'}>>> form2.validate()True>>> form2.errors{}因为我们的表单使用POST方法提交,如果单纯使用WTForms,我们在实例化表单类时需要首先把request.form传入表单类,而使用Flask-WTF时,表单类继承的FlaskForm基类默认会从request.form获取表单数据,所以不需要手动传入。注释:使用POST方法提交的表单,其数据会被Flask解析为一个字典,可以通过请求对象的form属性获取(request.form);使用GET方法提交的表单的数据同样会被解析为字典,不过要通过请求对象的args属性获取(request.args)。
if form.validate_on_submit():等价于 if request.method=='post' and form.validate():
3.3在模板中渲染错误信息错误信息会存在表单类的errors属性中,这是一个匹配作为表单字段的类属性到对应的错误消息列表的字典。
<form method="post"> {{ form.csrf_token }} {{ form.username.label }}<br> {{ form.username }}<br> {% for message in form.username.errors %} <small>至此,我们已经介绍了在Python中处理HTML表单的所有基本内容。完整的表单处理过程的流程图如图所示。