《Flask Web开发》学习(四)——Web表单

1.为何使用Flask-WTF

客户端发来的请求都会封装在request请求对象中,这些请求中会有一些表单数据需要处理。request.form可以获取这些表单数据。request请求对象提供的信息足够处理这些表单数据,但为了避免一些单调的任务,我们使用Flask-WTF。

2.跨站请求伪造保护

跨站请求伪造(CSRF)是指攻击者在被攻击者不知情的情况下,利用被攻击者的账号,向该账号的网站发送请求,以达到恶意目的,但在网站看来,这些请求都是合法的。

为了防止这种攻击,需要首先我们的app程序设置一个秘钥,Flask-WTF使用这个秘钥生成加密令牌,再用令牌验证请求中表单数据的真伪。设置秘钥的方法如下:

app.Flask(_name_)
app.config['SECRET_KEY'] = 'hard to guess string'

3.表单类

如下是一个web表单,Web表单用一个继承自FlaskForm的类表示,这个类中又包含一组字段,每个字段又用对象表示,对象可附属一个或多个验证函数,验证函数用来验证用户提交的输入值是否符合要求。下例中,两个构造函数name和submit的第一个参数是把表单渲染成HTML时使用的标号。name字段的第二个参数 validators是可选参数,DataRequired()是验证函数,用来在用户提交的数据之前验证数据。

from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

class NameForm(FlaskForm):    #Web表单用一个继承自FlaskForm的类表示
    name = StringField('What is your name?', validators=[DataRequired()])    #文本字段
    submit = SubmitField('Submit')    #提交按钮字段

4.把表单渲染成HTML

简单理解就是当我们处理用户需求时,视图函数可能会把一个表单实例传入模板,表单中的字段经模板调用后会渲染成HTML。而渲染工作最好能用Bootstrap中的表单样式。

5.在视图函数中处理表单

@app.route('/', methods=['GET', 'POST'])    
#methods参数告诉flask在URL映射中把这个视图函数注册为GET和POST请求的处理程序,提交表单作为POST请求进行处理更加便利
def index():
    name = None    #name用来存放表单中输入的有效名字,如果没有输入,其值为None
    form = NameForm()    #生成一个表单实例
    if form.validate_on_submit():  
#提交表单后,如果数据能被验证函数接受,validate_on_submit()返回True,否则返回False.True则处理表单数据,False则重新渲染表单
        name = form.name.data    #通过data属性获取名字,并赋值给局部变量name
        form.name.data = ''    #赋值后把data属性清空,从而清空表单字段
    return render_template('index.html', form=form, name=name)#渲染模板,name为表单中输入值

6.重定向和用户会话

可用性问题:用户输入名字后提交表单,然后点击浏览器的刷新按钮,会出现一个警告,要求在再次提交表单之前进行确认。这是因为刷新页面时浏览器会重新发送之前已经发送过的最后一个请求。如果这个请求是一个包含表单数据的POST请求,刷新页面后会再次提交表单。

解决方式:别让web程序把POST请求作为浏览器发送的最后一个请求。

实现方式:使用重定向作为POST请求的响应,而不是使用常规响应。POST下的常规响应的响应内容是HTML代码,浏览器可以直接显示;而重定向响应的内容是URL,浏览器收到这种响应后会向重定向的URL发起GET请求,显示页面内容。这样浏览器的最后一次请求就从POST变成了GET,所以刷新命令就能像预期那样正常使用了。这个技巧成为Post\重定向\Get模式

带来的新问题:上面讲到,重定向使最后一个响应变为GET响应,因此POST响应提前结束了,而这时使用form.name.data获取的用户名字数据也丢失了。但重定向请求也需要这个名字数据。为了保存这个名字,程序把用户名字由原来存储在局部变量name中改为存储在用户会话session中。

@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        session['name'] = form.name.data    #名字数据存储在session['name']中使得不随post结束而消失
        return redirect(url_for('index'))    #redirect()函数的参数是重定向的URL,用来生成HTTP重定向响应
    return render_template('index.html', form=form, name=session.get('name'))

猜你喜欢

转载自blog.csdn.net/theShepherd/article/details/86598006