尽管 Flask 的请求对象提供的信息足够用于处理 Web 表单,但有些任务很单调,并且要重复操做。好比,生成表单的 HTML 代码和验证提交的表单数据。html
Flask-WTF(http://pythonhosted.org/Flask-WTF/)扩展能够把处理 Web 表单的过程变成一种愉悦的体验。这个扩展对独立的 WTForms(http://wtforms.simplecodes.com)包进行了包装,方便集成到 Flask 程序中。python
默认状况下,Flask-WTF 能保护全部表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击。恶意网站把请求发送到被攻击者已登陆的其余网站时就会引起 CSRF 攻击。为了实现 CSRF 保护,Flask-WTF 须要程序设置一个密钥。Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。正则表达式
from flask import Flask app = Flask(__name__) app.config[SECRET_KEY] = 'aaaaaaaaaaaa'
app.config 字典可用来存储框架、扩展和程序自己的配置变量。使用标准的字典句法就能把配置值添加到 app.config 对象中。这个对象还提供了一些方法,能够从文件或环境中导入配置值。
SECRET_KEY 配置变量是通用密钥,可在 Flask 和多个第三方扩展中使用。如其名所示,加密的强度取决于变量值的机密程度。不一样的程序要使用不一样的密钥,并且要保证其余人不知道你所用的字符串。flask
建立forms.pybootstrap
from flask_wtf import FlaskForm from wtforms import BooleanField, StringField, SelectField, RadioField, FileField, PasswordField, SubmitField from wtforms.validators import Email, EqualTo, DataRequired, ValidationError, Length, Regexp from app import db from app.models import User class LoginForm(FlaskForm): """用户登陆表单""" username = StringField( label='用户名', validators=[ DataRequired('用户名不能为空') ], description='用户名', render_kw={ 'placeholder':'请输入用户名' } ) password = PasswordField( label="密码", validators=[ DataRequired('密码不能为空') ], description='密码', render_kw={ 'placeholder':'请输入密码' } ) submit = SubmitField( "登陆" ) def validate_username(self, field): username = field.data user = User.query.filter_by(username=username).count() if user == 0: raise ValidationError('用户名不正确') class RegisterForm(FlaskForm): username = StringField( label='用户名', validators=[ DataRequired('用户名不能为空'), Length(5,20, '长度在5~20之间'), ], description='用户名', render_kw={ 'placeholder':'请输入用户名' } ) email = StringField( label='邮箱', validators=[ DataRequired('不能为空'), Email('请输入正确的格式') ], description='邮箱' ) password = PasswordField( label='密码', validators=[ DataRequired('不能为空'), ], ) repassword = PasswordField( label='密码', validators=[ DataRequired('不能为空'), EqualTo('password','两次密码不一致') ] ) submit = SubmitField( '注册' ) def validate_username(self, field): """验证用户是否重复""" username = field.data user_count = User.query.filter_by(username=username).count() if user_count >= 1: raise ValidationError('用户名重复') def validate_email(self, filed): """验证邮箱是否注册""" email = filed.data user_count = User.query.filter_by(email=email).count() if user_count >= 1: raise ValidationError('邮箱已经注册')
WTForms支持的HTML标准字段
|字段类型|说明|
|---|---|
|StringField | 文本字段|
|TextAreaField |多行文本字段|
|PasswordField | 密码文本字段|
|HiddenField | 隐藏文本字段|
|DateField | 文本字段,值为 datetime.date 格式|
|DateTimeField |文本字段,值为 datetime.datetime 格式|
|IntegerField | 文本字段,值为整数|
|DecimalField |文本字段,值为 decimal.Decimal|
|FloatField | 文本字段,值为浮点数|
|BooleanField |复选框,值为 True 和 False|
|RadioField |一组单选框|
|SelectField | 下拉列表|
|SelectMultipleField | 下拉列表,可选择多个值|
|FileField | 文件上传字段|
|SubmitField | 表单提交按钮|
|FormField | 把表单做为字段嵌入另外一个表单|
|FieldList | 一组指定类型的字段|跨域
WTForms验证函数
|验证函数|说明|
|---|---|
|Email | 验证电子邮件地址|
|EqualTo |比较两个字段的值;经常使用于要求输入两次密码进行确认的状况|
|IPAddress | 验证 IPv4 网络地址|
|Length | 验证输入字符串的长度|
|NumberRange | 验证输入的值在数字范围内|
|Optional | 无输入值时跳过其余验证函数|
|Required | 确保字段中有数据|
|Regexp | 使用正则表达式验证输入值|
|URL | 验证 URL|
|AnyOf | 确保输入值在可选值列表中|
|NoneOf | 确保输入值不在可选值列表中|网络
@home.route('/login', methods=['GET', 'POST']) def login(): """登陆""" form = LoginForm() if form.validate_on_submit(): data = form.data user = User.query.filter_by(username=data['username']).first() if check_password_hash(user.password, data['password']): print(222222) login_user(user) print(1111) return redirect(url_for('home.index')) else: print(44444444) flash('登陆失败','err') return render_template('/home/user/login.html', form=form)
例经过参数 form 传入模板,在模板中能够生成一个简单的表单,以下所示:app
<form method="POST"> {{ form.hidden_tag() }} {{ form.name.label }} {{ form.name() }} {{ form.submit() }} </form>
即使能指定 HTML 属性,但按照这种方式渲染表单的工做量仍是很大,因此在条件容许的状况下最好能使用 Bootstrap 中的表单样式。Flask-Bootstrap 提供了一个很是高端的辅助函数,可使用 Bootstrap 中预先定义好的表单样式渲染整个 Flask-WTF 表单,而这些操做只需一次调用便可完成。使用 Flask-Bootstrap,上述表单可以使用下面的方式渲染:框架
{% import "bootstrap/wtf.html" as wtf %} {{ wtf.quick_form(form) }}
import 指令的使用方法和普通 Python 代码同样,容许导入模板中的元素并用在多个模板中。导入的 bootstrap/wtf.html 文件中定义了一个使用 Bootstrap 渲染 Falsk-WTF 表单对象的辅助函数。wtf.quick_form() 函数的参数为 Flask-WTF 表单对象,使用 Bootstrap 的默认样式渲染传入的表单。hello.py 的完整模板如示例 4-3 所示。
templates/index.html:使用 Flask-WTF 和 Flask-Bootstrap 渲染表单函数
{% extends "base.html" %} {% import "bootstrap/wtf.html" as wtf %} {% block title %}Flasky{% endblock %} {% block page_content %} <div class="page-header"> <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1> </div> {{ wtf.quick_form(form) }} {% endblock %}
模板的内容区如今有两部分。第一部分是页面头部,显示欢迎消息。这里用到了一个模板条件语句。Jinja2 中的条件语句格式为 {% if condition %}...{% else %}...{% endif %}。若是条件的计算结果为 True,那么渲染 if 和 else 指令之间的值。若是条件的计算结果为 False,则渲染 else 和 endif 指令之间的值。在这个例子中,若是没有定义模板变量 name,则会渲染字符串“Hello, Stranger!”。内容区的第二部分使用 wtf.quick_form() 函数渲染NameForm 对象。