flask-form文档
Form表单是Web应用中最基础的一部分。为了能处理Form表单,Flask-WTF扩展提供了良好的支持。
0x00 快速回忆
首先在模板html里面定义form的使用
,例如:
1 2 3 4 5 6 <form method ="POST" > {{form.hidden_tag()}} <p > 用户:{{form.name(size=20,id='name')}} {%for e in form.name.errors%}
然后定义一个表单类
,继承与Form
类:
1 2 3 4 5 6 7 8 class BaseLogin (Form ): name=StringField('name' ,validators=[DataRequired(message=u"用户名不能为空" ) ,Length(10 ,20 ,message=u'长度位于10~20之间' )],render_kw={'placeholder' :u'输入用户名' }) password=PasswordField('password' ,validators=[DataRequired(message=u"密码不能为空" ) ,Length(10 ,20 ,message=u'长度位于10~20之间' )],render_kw={'placeholder' :u'输入密码' })
然后在处理模板的函数中(如route.py ),将相应html
中的form赋值成我们定义的表单类
1 2 3 4 5 6 7 @app.route('/baselogin' ,methods=('POST' ,'GET' ) ) def baselogin (): form=BaseLogin() if form.validate_on_submit():
我们从页面输入的数据就会通过路由中的设置经过表单类
的验证
0x01 安装
0x02 开启CSRF保护
Flask-WTF提供了对所有Form表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)攻击的技术支持(通过添加动态token令牌的方式,关于CSRF可以自行在网上搜索相关内容,以后有时间可能会撰写相关内容)。
考虑到Flask扩展需要大量的配置信息,从这里开始,我们在在Flask根目录下新增config.py的配置文件:
启动CSRF保护,可以在config.py中定义2个变量:
1 2 CSRF_ENABLED = True SECRET_KEY = '123456'
其中SECRET_KEY用来建立加密的令牌,用于验证Form表单提交,在自己编写应用程序时,可以尽可能设置复杂一些,这样恶意攻击者将很难猜到密钥值。在__init__.py
文件中添加如下代码:
1 app.config.from_object('config')
此时完整的__init__.py
文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 __author__ = 'kikay' from flask import Flaskfrom flask.ext.bootstrap import Bootstrap app=Flask(__name__) bootstrap=Bootstrap(app) app.config.from_object('config' ) from app import views
最后,我们需要在响应的html模板的Form表单中加上如下语句:
或者:
其中的form是views.py中对应处理函数传递过来的Form对象名称,根据具体情况会有所变化。通过上面的配置,我们就启动了CSRF保护。
0x03 WTF表单
下面看一个简单的登录表单:
(1)通常我们会把一个表单里面的元素定义为1个类。下面我们在app包下新建forms.py文件,专门用于定义表单的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from flask.ext.wtf import Formfrom wtforms import StringField,PasswordFieldfrom wtforms.validators import DataRequired,Length __author__ = 'kikay' class BaseLogin (Form ): name=StringField('name' ,validators=[DataRequired(message=u"用户名不能为空" ) ,Length(10 ,20 ,message=u'长度位于10~20之间' )],render_kw={'placeholder' :u'输入用户名' }) password=PasswordField('password' ,validators=[DataRequired(message=u"密码不能为空" ) ,Length(10 ,20 ,message=u'长度位于10~20之间' )],render_kw={'placeholder' :u'输入密码' })
(2)模板baselogin.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <style > .base_login { float : none; display : block; margin-left : auto; margin-right :auto; width : 200px ; } </style > <title > BaseLogin</title > </head > <body > <div class ="base_login" > <h1 > 用户登录</h1 > <div > <form method ="POST" > {{form.hidden_tag()}} <p > 用户:{{form.name(size=20,id='name')}} {%for e in form.name.errors%} <span style ="color: red" > *{{e}}</span > {%endfor%} </p > <p > 密码:{{form.password(size=20,id='password')}} {%for e in form.password.errors%} <span style ="color: red" > *{{e}}</span > {%endfor%} </p > <p > <button style ="float: right" type ="submit" > 登录</button > </p > </form > </div > </div > </body > </html >
(3)views.py新增以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from flask import url_forfrom app.forms import BaseLogin @app.route('/baselogin' ,methods=('POST' ,'GET' ) ) def baselogin (): form=BaseLogin() if form.validate_on_submit(): flash(form.name.data+'|' +form.password.data) return redirect(url_for('success' )) else : return render_template('baselogin.html' ,form=form) @app.route('/success' ) def success (): return '<h1>Success</h1>'
效果如下:
看下源代码:
红色框中就是生成的CSRF保护的token令牌值。如果填入不能通过验证的值,比如admin/admin,将显示警告信息:
如果输入admin12345678/admin12345678将发生跳转:
前面已经实现了一个基础的表单,一些基本元素也涉及到了,还可以使用 Bootstrap 中预先定义好的表单样式渲染整个 Flask-WTF 表单:
1 2 3 4 5 6 7 8 9 10 11 12 {%extends 'bootstrap/base.html'%} {%import 'bootstrap/wtf.html' as wtf%} {%block content%} <div class ="container col-lg-3 col-lg-offset-3" > <div class ="page-header" > <h3 > WTF-Login</h3 > </div > <div > {{wtf.quick_form(form)}} </div > </div > {%endblock%}
其他部分的修改很简单,就不多讲。
0x04 Flash消息
在表单上面显示一个消息,提示用户用户名或密码错误。
1 2 3 4 5 6 7 8 9 10 11 12 13 @app.route('/baselogin2' , methods=('POST' , 'GET' ) ) def baselogin2 (): form = BaseLogin() if form.validate_on_submit(): username = form.name.data if username == 'admin' : return redirect(url_for('success' )) else : flash(u'用户名不正确' ) return render_template('mtflogin.html' , form=form)
模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 {%extends 'bootstrap/base.html'%} {%import 'bootstrap/wtf.html' as wtf%} {%block content%} <div class ="container col-lg-3 col-lg-offset-3" > <div class ="page-header" > <h3 > WTF-Login</h3 > </div > <div > {%for message in get_flashed_messages()%} <div class ="alert alert-warning" > <button type ="button" class ="close" data-dismiss ="alert" > × </button > {{message}} </div > {%endfor%} {{wtf.quick_form(form)}} </div > </div > {%endblock%}
效果:
0x05会话保持
利用session机制完成会话保持:
1 2 3 4 5 6 7 8 9 10 11 12 13 @app.route('/baselogin2' , methods=('POST' , 'GET' ) ) def baselogin2 (): form = BaseLogin() if form.validate_on_submit(): name=session.get('name' ) if name is None and name!=form.name.data: flash(u'您已经切换了用户' ) return redirect(url_for('success' )) elif name==None : session['name' ]=form.name.data return render_template('mtflogin.html' , form=form)
0x06自定义验证器
开始做一个可复用的验证器,简单的namefield验证器
1 2 3 4 5 6 class MyForm (Form ): name = StringField('Name' , [InputRequired()]) def validate_name (form, field ): if len (field.data) > 50 : raise ValidationError('Name must be less than 50 characters' )
我们可以将函数放在类中,也可以将函数放在类外任何可以调用到函数的地方,如下:
1 2 3 4 5 6 def my_length_check (form, field ): if len (field.data) > 50 : raise ValidationError('Field must be less than 50 characters' ) class MyForm (Form ): name = StringField('Name' , [InputRequired(), my_length_check])
我们也可以通过创建一个工厂来让验证器更强大
1 2 3 4 5 6 7 8 9 10 def length (min =-1 , max =-1 ): message = 'Must be between %d and %d characters long.' % (min , max ) def _length (form, field ): l = field.data and len (field.data) or 0 if l < min or max != -1 and l > max : raise ValidationError(message) return _length class MyForm (Form ): name = StringField('Name' , [InputRequired(), length(max =50 )])
现在我们创建了一个可控制长度的字符串长度验证器,下面我们将验证器做的可复用性更高,并且让用户可以自定义自己的错误消息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Length (object ): def __init__ (self, min =-1 , max =-1 , message=None ): self .min = min self .max = max if not message: message = u'Field must be between %i and %icharacters long.' % (min , max ) self .message = message def __call__ (self, form, field ): l = field.data and len (field.data) or 0 if l < self .min or self .max != -1 and l > self .max : raise ValidationError(self .message) length = Length
https://blog.csdn.net/qq_35562816/article/details/80002315