1.Flask-WTF
Flask-WTF扩展可以把处理Web表单的过程变成一种愉悦的体验。这个扩展对独立的WTForms包进行了包装,方便集成到Flask应用中。
Flask-WTF及其依赖可使用pip安装:
pip install flask-wtf
配置:
与其他多数扩展不同,Flask-WTF无须在应用层初始化,但是它要求应用配置一个密钥。密钥是一个由随机字符构成的唯一字符串,通过加密或签名以不同的方式提升应用的安全性。Flask使用这个密钥保护用户会话,以防被篡改。每个应用的密钥应该不同,而且不能让任何人知道。
app.config['SECRET_KEY'] = 'you cant guess it pig haha'
Flask-WTF之所以要求应用配置一个密钥,是为了防止表单遭到跨站请求伪造(CSRF,cross-site request forgery)攻击。恶意网站把请求发送到被攻击者已登录的其他网站时,就会引发CSRF攻击。Flask-WTF为所有表单生成安全令牌,存储在用户会话中。令牌是一种加密签名,根据密钥生成
2.表单类
使用Flask-WTF时,在服务器端,每个Web表单都由一个继承自FlaskForm的类表示。这个类定义表单中的一组字段,每个字段都用对象表示。字段对象可附属一个或多个验证函数。验证函数用于验证用户提交的数据是否有效
class NameForm(FlaskForm): name = StringField('What is your name?', validators=[DataRequired()]) submit = SubmitField('Submit')
WTForms支持的HTML标准字段:
WTForms验证函数:
3.把表单渲染成HTML
单字段是可调用的,在模板中调用后会渲染成HTML。假设视图函数通过form参数把一个NameForm实例传入模板,在模板中可以生成一个简单的HTML表单,如下所示:
<form method="POST"> {{ form.hidden_tag() }} {{ form.name.label }} {{ form.name() }} {{ form.submit() }} </form>
别忘了在视图层传值哦:
@app.route('/') def hello_world(): form = NameForm() return render_template('index.html', form = form)
生成表单:
注意,除了name和submit字段,这个表单还有个form.hidden_tag()元素。这个元素生成一个隐藏的字段,供Flask-WTF的CSRF防护机制使用
当然,这种方式渲染出的表单还很简陋。调用字段时传入的任何关键字参数都将转换成字段的HTML属性。例如,可以为字段指定id或class属性,然后为其定义CSS样式:
<form method="POST"> {{ form.hidden_tag() }} {{ form.name.label }} {{ form.name(id='my-text-field') }} {{ form.submit() }} </form>
4.在视图函数中处理表单
视图函数hello_world()有两个任务:一是渲染表单,二是接收用户在表单中填写的数据
@app.route('/', methods=['GET', 'POST']) def hello_world(): name = None form = NameForm() if form.validate_on_submit(): name = form.name.data form.name.data = '' return render_template('index.html', form=form, name=name)
pp.route
装饰器中多出的methods参数告诉Flask,在URL映射中把这个视图函数注册为GET和POST请求的处理程序。如果没指定methods参数,则只把视图函数注册为GET请求的处理程序
首次进入主页的页面:
输入姓名后提交:
5.重定向和用户会话
在上面的程序中,用户输入名字后提交表单,然后点击浏览器的刷新按钮,会看到一个莫名其妙的警告,要求在再次提交表单之前进行确认。之所以出现这种情况,是因为刷新页面时浏览器会重新发送之前发送过的请求。如果前一个请求是包含表单数据的POST请求,刷新页面后会再次提交表单。多数情况下,这并不是我们想执行的操作,因此浏览器才要求用户确认。
所以我们应该使用重定向作为POST请求的响应,而不是使用常规响应,而且可以把数据存储在用户会话中,使之不会丢失
完善后的代码如下:🍟
@app.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): session['name'] = form.name.data return redirect(url_for('index')) return render_template('index.html', form=form, name=session.get('name'))
6.闪现消息
请求完成后,有时需要让用户知道状态发生了变化,可以是确认消息、警告或者错误提醒。一个典型例子是,用户提交有一项错误的登录表单后,服务器发回的响应重新渲染登录表单,并在表单上面显示一个消息,提示用户名或密码无效。Flask本身内置这个功能。
flash()函数可实现这种效果。
再次改进上面的程序:
@app.route('/', methods=['GET', 'POST']) def index(): form = NameForm() if form.validate_on_submit(): old_name = session.get('name') if old_name is not None and old_name != form.name.data: flash('你更换了你的名字!') session['name'] = form.name.data return redirect(url_for('index')) return render_template('index.html', form=form, name=session.get('name'))
仅调用flash()
函数并不能把消息显示出来,应用的模板必须渲染这些消息:
{% for message in get_flashed_messages() %} {{ message }} {% endfor %}