Flask系列教程(9)——Flask-WTF

原创 2017年07月07日 12:27:12

Flask-WTF

Flask-WTF是简化了WTForms操作的一个第三方库。WTForms表单的两个主要功能是验证用户提交数据的合法性以及渲染模板。当然还包括一些其他的功能:CSRF保护,文件上传等。安装Flask-WTF默认也会安装WTForms,因此使用以下命令来安装Flask-WTF:

pip install flask-wtf

表单验证:安装完Flask-WTF后。来看下第一个功能,就是用表单来做数据验证,现在有一个forms.py文件,然后在里面创建一个RegistForm的注册验证表单:

class RegistForm(Form):
    name = StringField(validators=[length(min=4,max=25)])
    email = StringField(validators=[email()])
    password = StringField(validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')])
    confirm = StringField()

在这个里面指定了需要上传的参数,并且指定了验证器,比如name的长度应该在4-25之间。email必须要满足邮箱的格式。password长度必须在6-10之间,并且应该和confirm相等才能通过验证。

写完表单后,接下来就是regist.html文件:

<form action="/regist/" method="POST">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>邮箱:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>确认密码:</td>
<td><input type="password" name="confirm"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>

再来看视图函数regist

@app.route('/regist/',methods=['POST','GET'])
def regist():
    form = RegistForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User(name=form.name.data,email=form.email.data,password=form.password.data)
        db.session.add(user)
        db.session.commit()
        return u'注册成功!'
    return render_template('regist.html')

RegistForm传递的是request.form进去进行初始化,并且判断form.validate会返回用户提交的数据是否满足表单的验证。

渲染模板:form还可以渲染模板,让你少写了一丢丢的代码,比如重写以上例子,RegistForm表单代码如下:

class RegistForm(Form):
    name = StringField(u'用户名:',validators=[length(min=4,max=25)])
    email = StringField(u'邮箱:'validators=[email()])
    password = StringField(u'密码:',validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')])
    confirm = StringField(u'确认密码:')

以上增加了第一个位置参数,用来在html文件中,做标签提示作用。

app中的视图函数中,修改为如下:

@app.route('/regist/',methods=['POST','GET'])
def regist():
    form = RegistForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User(name=form.name.data,email=form.email.data,password=form.password.data)
        db.session.add(user)
        db.session.commit()
        return u'注册成功!'
    return render_template('regist.html',form=form)

以上唯一的不同是在渲染模板的时候传入了form表单参数进去,这样在模板中就可以使用表单form变量了。

接下来看下regist.html文件:

<form action="/regist/" method="POST">
<table>
<tr>
<td>{{ form.name.label }}</td>
<td>{{ form.name() }}</td>
</tr>
<tr>
<td>{{ form.email.label }}</td>
<td>{{ form.email() }}</td>
</tr>
<tr>
<td>{{ form.password.label }}</td>
<td>{{ form.password() }}</td>
</tr>
<tr>
<td>{{ form.confirm.label }}</td>
<td>{{ form.confirm() }}</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>

Field常用参数:在使用Field的时候,经常需要传递一些参数进去,以下将对一些常用的参数进行解释:
* label(第一个参数):Field的label的文本。
* validators:验证器。
* id:Field的id属性,默认不写为该属性名。
* default:默认值。
* widget:指定的html控件。

常用Field:
* BooleanField:布尔类型的Field,渲染出去是checkbox
* FileField:文件上传Field。

# forms.py
from flask_wtf.file import FileField,FileAllowed,FileRequired
class UploadForm(FlaskForm):
    avatar = FileField(u'头像:',validators=[FileRequired(),FileAllowed([])])

# app.py
@app.route('/profile/',methods=('POST','GET'))
def profile():
    form = ProfileForm()
    if form.validate_on_submit():
        filename = secure_filename(form.avatar.data.filename)
     form.avatar.data.save(os.path.join(app.config['UPLOAD_FOLDER'],filename))
        return u'上传成功'
    return render_template('profile.html',form=form)
  • FloatField:浮点数类型的Field,但是渲染出去的时候是text的input。
  • IntegerField:整形的Field。同FloatField。
  • RadioField:radio类型的input。表单例子如下:
# form.py
class RegistrationForm(FlaskForm):
    gender = wtforms.RadioField(u'性别:',validators=[DataRequired()])

模板文件代码如下:

<tr>
<td>
{{ form.gender.label }}
</td>
<td>
{% for gender in form.gender %}
{{ gender.label }}
{{ gender }}
{% endfor %}
</td>
</tr>

app.py文件的代码如下,给gender添加了choices

@app.route('/register/',methods=['POST','GET'])
def register():
    form = RegistrationForm()
    form.gender.choices = [('1',u'男'),('2',u'女')]
    if form.validate_on_submit():
        return u'success'

    return render_template('register.html',form=form)
  • SelectField:类似于RadioField。看以下示例:
# forms.py
class ProfileForm(FlaskForm):
    language = wtforms.SelectField('Programming Language',choices=[('cpp','C++'),('py','python'),('text','Plain Text')],validators=[DataRequired()])

再来看app.py文件:

@app.route('/profile/',methods=('POST','GET'))
def profile():
    form = ProfileForm()
    if form.validate_on_submit():
        print form.language.data
        return u'上传成功'
    return render_template('profile.html',form=form)

模板文件为:

<form action="/profile/" method="POST">
{{ form.csrf_token }}
{{ form.language.label }}
{{ form.language() }}
<input type="submit">
</form>
  • StringField:渲染到模板中的类型为<input type='text'>,并且是最基本的文本验证。
  • PasswordField:渲染出来的是一个passwordinput标签。
  • TextAreaField:渲染出来的是一个textarea

常用的验证器:数据发送过来,经过表单验证,因此需要验证器来进行验证,以下对一些常用的内置验证器进行讲解:
* DataRequired:数据需要。即该值一定需要上传,才能通过验证。
* Email:验证上传的数据是否为邮箱。
* EqualTo:验证上传的数据是否和另外一个字段相等,常用的就是密码和确认密码两个字段是否相等。
* InputRequired:原始数据的需要验证。如果不是特殊情况,应该使用InputRequired
* Length:长度限制,有min和max两个值进行限制。
* NumberRange:数字的区间,有min和max两个值限制,如果处在这两个数字之间则满足。
* Regexp:自定义正则表达式。
* URL:必须要是URL的形式。
* UUID:验证UUID

自定义验证字段:使用validate_fieldname(self,field)可以对某个字段进行更加详细的验证,如下:

class ProfileForm(FlaskForm):
    name = wtforms.StringField('name',[validators.InputRequired()])
    def validate_name(self,field):
        if len(field.data) > 5:
            raise wtforms.ValidationError(u'超过5个字符')

CSRF保护:在flask的表单中,默认是开启了csrf保护功能的,如果你想关闭表单的csrf保护,可以在初始化表单的时候传递csrf_enabled=False进去来关闭csrf保护。如果你想关闭这种默认的行为。如果你想在没有表单存在的请求视图函数中也添加csrf保护,可以开启全局的csrf保护功能:

csrf = CsrfProtect()
csrf.init_app(app)

或者是针对某一个视图函数,使用csrf.protect装饰器来开启csrf保护功能。并且如果已经开启了全局的csrf保护,想要关闭某个视图函数的csrf保护功能,可以使用csrf.exempt装饰器来取消本视图函数的保护功能。

AJAX的CSRF保护:AJAX中要使用csrf保护,则必须手动的添加X-CSRFTokenHeader中。但是CSRF从哪里来,还是需要通过模板给渲染,而Flask比较推荐的方式是在meta标签中渲染csrf,如下:

<meta name="csrf-token" content="{{ csrf_token() }}">

如果要发送AJAX请求,则在发送之前要添加CSRF,代码如下(使用了jQuery):

var csrftoken = $('meta[name=csrf-token]').attr('content')
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken)
        }
    }
})

### 如果想深入学习Flask,可以观看这套免费Flask教学视频:Flask入门到项目实战

python flask 总结以及一些各种传值问题

这几天刚用了用flask开发了一些网页,发现有很多的传值细节都很难搞定。楼主在这里列举一些例子,不过很多的东西楼主也没用过,以后慢慢补充。 1. 首先安装flask插件 2. 导入包 from ...

自行编写代码解决 WTForm 无纯 Button 按钮的问题——input篇

在使用 Flask 框架的过程中,会时常使用到 WTForm 这个库。然而在使用中却发现,该库提供的 HTML 元素并不完整,在我们需要使用单纯的 HTML 按钮时,却发现库并不提供,那么我们只能自己...
  • tiwoo
  • tiwoo
  • 2015年05月25日 03:41
  • 667

Flask系列教程(4)——SQLAlchemy数据库

flask入门(数据库)数据库是一个网站的基础,在Flask中可以自由的使用MySQL、PostgreSQL、SQLite、Redis、MongoDB来写原生的语句实现功能,也可以使用更高级别的数据库...

Flask系列教程(10)——上下文

flask上下文Flask项目中有两个上下文,一个是应用上下文(app),另外一个是请求上下文(request)。请求上下文request和应用上下文current_app都是一个全局变量。所有请求都...

Flask系列教程(2)——URL和视图

flask入门(URL)flask简介:flask是一款非常流行的Python Web框架,出生于2010年,作者是Armin Ronacher,本来这个项目只是作者在愚人节的一个玩笑,后来由于非常受...

Flask系列教程(5)——视图高级

flask入门(视图高级)类视图:之前我们接触的视图都是函数,所以一般简称视图函数。其实视图也可以基于类来实现,类视图的好处是支持继承,但是类视图不能跟函数视图一样,写完类视图还需要通过app.add...

Flask系列教程(一)-----------入门

安装flask pip3 install flask 使用git做版本管理 mkdir flask_tutorials cd flash_tutorilas git init 过滤文件 tou...

Flask系列教程(三)---------------通过模板创建视图(一)

在本章中,我们会使用Flask Jinja内置的模板语言,基于SQLAlchemy模型动态地创建HTML页面。我们会学到Jinja的一些函数,它们可以自动生成HTML,还可以对数据进行某些修改后再将其...

Flask系列教程(二)--------------使用SQLAlchemy创建数据模型

创建user表 Z:\python\flask_tutorials>python manage.py shell >>> db.create_all() 2016-12-30 22:58:44,661...

Flask系列教程(8)——Flask-Migrate

Flask-Migrate在实际的开发环境中,经常会发生数据库修改的行为。一般我们修改数据库不会直接手动的去修改,而是去修改ORM对应的模型,然后再把模型映射到数据库中。这时候如果有一个工具能专门做这...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Flask系列教程(9)——Flask-WTF
举报原因:
原因补充:

(最多只允许输入30个字)