python flask 表单处理Flask-WTF

  • A+
所属分类:python

涉及到的插件和包有Flask-WTF,WTForms。内容有表单的创建使用流程,一些最佳实践,还有在页面显示提示消息的简单方式,配合Flask内置的 flash()

Flask的requset对象包含了client端发送过来的所有请求,在request.form中就有POST方法提交过来的表单数据。直接使用这些数据可以搞定表单的操作,不过不方便,于是有了Flask-WTF这个插件,它将WTForms这个包嵌入Flask里,简化Flask下的使用。pip安装会把插件的以来也安装进来:

WTForms应该也同时被安装了。

跨站请求伪造(Cross-Site Request Forgery,CSRF) 保护

CSRF的原理不具体讲了,很简单,感兴趣直接网上搜即可。

Flask-WTF默认提供对CSRF的保护。应用里需要设置一个加密用的key,Flask-WTF利用这个key生成一个加密的记号来验证request带过来的表单数据。看看实例:

app.config 是应用保存配置的一个字典。可以直接在字典里增加配置。SECRET_KEY这个配置变量被Flask和一些第三方插件使用,对不同的应用配置不同的值增加点可靠性。

另外,这个值最好放到环境变量里,直接写到代码里不太好。

表单类

使用Flask-WTF的时候,每一个表单都是类的形式,这个类需要继承自Form。这个类里定义一些代表表单各类域的对象,每个对象可以有多个验证器(validators)。验证器可以确保用户的输入是有效的。

原例子:

表单中的域在类中都定义成类变量。上例中,NameForm类里有文本域name和提交按钮submit两个。StringField代表有type="text"属性的<input>元素。SubmitField代表有type="submit"属性的<input>元素。构造器的第一个参数是后续渲染表单时候用到的标签(label)。

下例是一个带有文本域和提交按钮的表单例子:

表单中的域在类中都定义成类变量。上例中,LoginForm类里有字符串域openid,复选框remember_me, 密码域password,提交按钮submit。分别代表小面信息:

构造器的第一个参数是后续渲染表单时候用到的标签(label)。

StringField里的validators参数定义了一些验证器,这些验证器会在用户提交数据前检查数据是否有效。Required验证器确保提交的内容不能为空。

WTForms提供的各种HTML域:

WTForms提供的各种验证器:

渲染表单

表单的各类域在模板中渲染时表现为可调用的对象。假设将一个NameForm的实例name作为参数传入模板。

这样渲染出来的页面不美观,可以尝试改进下,在调用里传入一些参数,这些参数都会被转化为这个域的属性。然后你可以用CSS自己搞定美化问题:

上述方式显然很累,之前加入了Bootstrap的支持,Flask-Bootstrap插件其实也对Flask-WTF创建的表单有高层接口的支持,可以用Bootstrap来修饰一下。然后表单的模板就可以简单写成:

从其他模板import个函数进来之前提到过,wtf.quick_form函数接受一个Flask-WTF的表单,然后用Bootstrap默认的样式渲染。

现在,首页index.html已经改为:

这里还用了一个if else结构,如果传入了name,就显示传入的值,否则就显示Stranger。

表单的各类域在模板中渲染时表现为可调用的对象。假设将一个LoginForm的实例openid作为参数传入模板。

 

视图函数中的表单处理

修改hello.py,在index()里处理表单数据。

可以注意到,在app.route装饰器增加了methods参数,这里是把index()注册为GET和POST请求的处理者。如果不提供methods这个参数,试图函数默认只处理GET请求。

这里对index()增加视图函数对POST请求的支持是必须的,因为用户的提交操作使用POST请求更方便处理。使用GET请求来提交表单也可以,但是GET请求的数据都是附加在URL后面作为请求字符串,在浏览器的地址栏可以看到。由此,以及一些其他原因,表单的提交通常都是用POST请求完成的。

继续看改动后的代码,form.validate_on_submit()这个方法,只在用户提交了数据并且数据通过验证器的检查之后,才返回True,其他时候都返回False。用这个方法判断是否对模板进行处理。

看下一般处理流程。用户第一次访问这个应用,使用的是GET请求,不带数据,form.validate_on_submit()这个方法返回False,return就返回一个空白的表单,name值是None。

用户提交了表单后,sercer收到携带数据的POST请求,form.validate_on_submit()这个方法会启动之前设置的Required()验证器,这里name不为空就通过验证,form.validate_on_submit()返回True。然后提取出表单数据保存下来,把表单数据清空。再把name和表单传入render_template(),重新渲染的模板就有了变化。

weinxin
微信公众号
扫一扫关注运维生存时间公众号,获取最新技术文章~
默北

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: