第二章中介绍的request
对象公开了全部客户端发送的请求信息。特别是request.form
能够访问POST
请求提交的表单数据。html
尽管Flask的request
对象提供的支持足以处理web表单,但依然有许多任务会变得单调且重复。表单的HTML代码生成和验证提交的表单数据就是两个很好的例子。git
Flask-WTF扩展使得处理web表单能得到更愉快的体验。该扩展是一个封装了与框架无关的WTForms包的Flask集成。github
Flask-WTF和它的依赖集能够经过pip来安装:web
(venv) $ pip install flask-wtf
默认状况下,Flask-WTF保护各类形式对跨站请求伪造(CSRF)攻击。一个CSRF攻击发生在一个恶意网站发送请求给受害者登陆的其余网站。flask
为了实现CSRF保护,Flask-WTF须要应用程序去配置一个加密密钥。Flask-WTF使用这个密钥去生成加密令牌用于验证请求表单数据的真实性。示例4-1展现如何配置加密密钥。bootstrap
示例4-1. hello.py:Flask-WTF配置安全
app = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string'
app.config
字典一般是框架、扩展或应用程序自身存放配置变量的地方,可使用标准字典语法添加配置值到app.config
中。配置对象提供方法来从文件或环境导入配置值。app
SECRET_KEY
配置变量做为Flask和一些第三方扩展的通用加密密钥。加密的强度取决于这个变量的值。给你构建的每一个应用程序选择不一样的密钥,并确保这个字符串不被其余任何人知道。框架
注:为了提升安全性,密钥应该存储在一个环境变量中,而不是嵌入到代码中。这个会在第7章中描述。函数
使用Flask-WTF时,每一个web表单是由继承自Form
类的子类来展示的。该类在表单中定义了一组表单域,每一个都表示为一个对象。每一个表单域均可以链接到一个或多个validators;validators
是一个用于检查用户提交的输入是否合法的函数。
示例4-2展现了一个拥有文本框和提交按钮的简单web表单。
示例4-2. hello.py:表单类定义
from flask.ext.wtf import Form from wtforms import StringField, SubmitField from wtforms.validators import Required class NameForm(Form): name = StringField('What is your name?', validators=[Required()]) submit = SubmitField('Submit')
表单中的域被定义为类的变量,且每一个类的变量都指定一个表单域类型对象。在上一个示例中,NameForm
表单有一个name
文本框和submit
提交按钮。StringField
类表示一个type="text"
属性的<input>
标签。SubmitField
类表示一个type="submit"
属性的<input>
标签。表单域构造函数的第一个参数是一个label
,在渲染表单到HTML时会使用。
StringField
构造函数包含可选参数validators
,它定义了一组检查来验证用户提交的数据。Required()
验证确保提交的表单域不为空。
注:Flask-WTF扩展定义了表单基类,因此它从flask.ext.wtf导入。表单域、验证都是直接从WTForms包中导入。
表格4-1展现了一组WTForms支持的标准表单域。
表格4-1. WTForms标准HTML表单域
表格4-2展现了一组WTForms内建验证。
表格4-2. WTForms验证
表单域是可调用的,调用时从模板渲染它们到HTML。假设视图函数传递一个参数名为form
的NameForm
实例给模板,模板就会生成一个简单的HTML表单,以下所示:
<form method="POST"> {{ form.name.label }} {{ form.name() }} {{ form.submit() }} </form>
固然,结果是什么都没有。为了改变表单的外观显示,任何发送给该表单域的参数会被转换为HTML表单域属性;例如,你能够给定表单域id
或class
属性,而后定义CSS样式:
<form method="POST"> {{ form.name.label }} {{ form.name(id='my-text-field') }} {{ 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来渲染Flask-WTF表单。wtf.quick_form()
函数传入Flask-WTF表单对象并使用默认Bootstrap样式渲染它。示例4-3展现了完整的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 %}
目前模板的内容区有两块。第一块是类为page-header
的div输出一个问候语。这里使用了模板条件判断语句。在Jinja2中格式为{% if variable %}...{% else %}...{% endif %}
。若是判断条件为True
则渲染if
和else
之间的内容。若是判断条件为False
则渲染else
和endif
之间的内容。示例模板会渲染字符串“Hello, Stranger!”当name
模板参数未定义的时候。第二块内容使用wtf.quick_form()
函数渲染NameForm
对象。