flask(十一):表单(一)

目录

HTML表单

使用Flask-WTF处理表单

安装flask-wtf及其依赖

​​​​​​​定义WTFrom表单

​​​​​​​常用的WTFroms字段

​​​​​​​验证器(validator)

​​​​​​​继承Form类生成表单

​​​​​​​继承FlaskForm类生成表单

​​​​​​​添加额外的属性

​​​​​​​在模板中渲染表单

在web程序中,表单是和用户交互最常见的方式之一。用户注册、登录、撰写文章、编辑设置,无一不用到表单。不过,表单的处理不简单。要创建表单,验证用户输入的内容,向用户显示错误提示,还要获取并保存数据。WTForms可以做这些事情,WTForm是一个使用python编写的表单库,它使得表单的定义、验证(服务器端)和处理变得非常轻松。接下来介绍一下web程序中处理表单的方法和技巧。

HTML表单

在html中,表单通过

标签来创建,表单中的字段使用标签定义。下面是一个简单的表单:




    
    Title



    
    
    
    
         
    

用浏览器打开,可以看到以下内容:

flask(十一):表单(一)_第1张图片

WTForms支持在python中使用类定义表单,然后通过类定义生成对应的HTML代码,这个方式更方便,易于重用。因此,触发是非常简单的程序,或者想让表单的定义更加灵活,都在不会在模板中直接使用HTML编写表单。

使用Flask-WTF处理表单

扩展Flask-WTF继承了WTFforms,使用它可以在flask中更方便的使用WTFroms。Flask-WTF将表单数据解析、CSRF保护、文件上传等功能与flask集成。

​​​​​​​安装flask-wtf及其依赖

激活pipenv环境:pipenv shell

flask(十一):表单(一)_第2张图片

 

查看已安装模块:pip list

flask(十一):表单(一)_第3张图片

 

 

安装flask-wtf:pipenv install flask-wtf

flask(十一):表单(一)_第4张图片

 

查看是否安装成功:pip list

flask(十一):表单(一)_第5张图片

 

flask-wtf默认为每个表单启动CSRF保护,它为我们自动生成和验证CSRF令牌。默认情况下,flask-wtf使用程序密钥来对CSRF令牌进行签名(token),所以我们需要为程序设置密钥:

app.secret_key="secret key"

​​​​​​​定义WTFrom表单

使用WTFroms创建表单时,表单由python类表示,这个类继承从WTFroms导入的Form基类。一个表单由若干个输入字段组成,这些字段分别用表单类的类属性表示(字段即field,可以简单理解为表单内的输入框、按钮等部件),下面定义了一个LoginForm类,最终会生成像之前定义的HTML表单:

cmd界面运行:

# -*- coding: utf-8 -*-#
from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length

class LoginForm(Form):
    username = StringField("Username", validators=[DataRequired()])
    password = PasswordField("Password", validators=[DataRequired(), Length(8, 128)])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

每个字段属性通过实例化WTFroms提供的字段类来表示。字段属性的名称将作为对应HTML元素的name属性以及id属性值。字段属性名称大小写敏感,不能以下划线或validate开头。这里的LoginFrom表单类中定义了四个字段:

文本字段StringField,密码字段PasswordField,勾选框字段BooleanField和提交按钮字段SubmitField。

字段类从wtforms包导入,邮箱字段最终生成的HTML代码相同,不过WTForms会在表单提交后根据表单类中字段的类型对数据进行处理,转换成对应的python类型,以便在python脚本中对数据进行处理。

​​​​​​​常用的WTFroms字段

字段类

说明

对应的HTML表示

BooleanField

复选框,值会被处理为True或False

DateField

文本字段,值会被处理为datetime.date对象

DateTimeField

文本字段,值会被处理为datetime.datetime对象

FileField

文件上传字段

FloatField

浮点数字段,值会被处理为浮点型

IntergerField

整数字段,值会被处理为整型

RadioField

一组单选按钮

SelectField

下拉列表

SelectMultipleField

多选下拉列表

SubmitField

提交按钮

StringField

文本字段

HiddenField

隐藏文本字段

PasswordField

密码文本字段

TextAreaField

多行文本字段

 

通过实例化字段类时传入的参数,我们可以对字段进行设置,字段类构造方法接收的常用参数如下:

参数

说明

label

字段标签

render_kw

一个字典,用来设置对应的HTML标签的属性,比如传入{placeholder="your name"},渲染后的HTML代码会将标签的placeholder属性设置为your name

validators

一个列表,包含一系列验证器,会在表单提交后被逐一调用验证表单数据

default

字符串或可调用对象,用来为表单字段设置默认值

​​​​​​​验证器(validator)

在WTForms中,验证器(validator)是一系列用于验证字段数据的类,我们在实例化字段类时使用validators关键字来指定附加的验证器列表。验证器从wtfroms.validators模块中导入,常用的验证器如下表:

验证器

说明

DataRequired(message=None)

验证数据是否有效

Email(message=None)

验证Email地址

EqualTo(filename,message=None)

验证两个字段的值是否相同

InputRequired(message=None)

验证是否有数据

Length(min=-1,max=-1,message=None)

验证输入值长度是否在给定范围内

NumberRange(min=None,max=None,message=None)

验证输入数字是否在给定范围内

Optional(strip_whitespace=True)

允许输入值为空,并跳过其它验证

Regexp(regex,flags=0,message=None)

使用正则表达式验证输入值

URL(require_tId=True,message=None)

验证URL

AnyOf(values,message=None,values_formatter=None)

确保输入值在可选值列表中

NoneOf(values,message=None,values_formatter=None)

确保输入值不在可选值列表中

在实例化验证类时,message参数用来传入自定义错误消息,如果没有设置则使用内置的英文错误消息。

validators参数接收一个可调用对象组成的列表。内置的验证器通过实现了__call__()方法的类表示,所以我们需要在验证器后添加括号。在name和password字段中,我们都用了DataRequired验证器,用来验证输入的数据是否有效。另外,password字段里还添加了一个Length验证器,用来验证输入的数据长度是否在给定的范围内。验证器的第一个参数一般为错误提示消息,我们可以使用message关键字传递参数,通过传入自定义错误信息覆盖内置信息,比如:

name = StringField("Your Name",validators=[DataRequired(message="名字不能为空")])

​​​​​​​继承Form类生成表单

以上一节使用WTForms创建的LoginForm类为例,实例化表单类,然后将实例属性转换为字符串或者直接调用就可以获取表单字段对应的HTML代码

>>> class LoginForm(Form):

...     username = StringField("Username", validators=[DataRequired()])

...     password = PasswordField("Password", validators=[DataRequired(), Length(8, 128)])

...     remember = BooleanField("Remember me")

...     submit = SubmitField("Log in")

...

>>> form = LoginForm()

>>> form.username()

''

>>> form.password()

''

>>> form.submit()

''

>>> form.remember()

''

 

字段的

>>> form.username.label()

''

>>> form.submit.label()

''

 

​​​​​​​继承FlaskForm类生成表单

当使用Flask-WTF定义表单时,我们仍然使用WTForms提供的字段类和验证器,创建的方式也完全相同,只不过表单类要继承flask-WTF提供的FlaskForm类。FlaskFrom类继承自From类,进行了一些设置,并附加了一些辅助方法,以便与Flask集成。

下面的例子是继承FlaskForm类的LoginForm表单:

from flask_wtf import FlaskForm
from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length


class LoginForm(FlaskForm):
    username = StringField("Username", validators=[DataRequired()])
    password = PasswordField("Password", validators=[DataRequired(), Length(8, 128)])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

配置键WTF_CSRF_ENABLED用来设置是否开启CSRF保护,默认为True。Flaask-WTF会自动在实例化表单时添加一个包含CSRF令牌值的隐藏字段,名为csrf_token。

​​​​​​​添加额外的属性

在创建HTML表单时,我经常会需要使用HTML元素的其它属性来对字段进行设置。比如class属性设置对应的CSS类为字段添加样式;使用placehodler属性设置站位文本。默认情况下,WTForms输出的字段HTML代码只会包含id和name属性,属性值均为表单类中对应的字段属性名称,如果需要添加额外的属性通常有2种方法:

使用render_kw属性

比如下面为username字段使用render_kw设置了placeholder HTML属性:

username = StringField("Username", render_kw={"placeholder":"Your Username"})

这个字段被调用后输出的HTML代码是:

调用字段时传入

在调用字段属性时,通过添加括号使用关键字参数的形式也可以传入字段额外的HTML属性:

>>> form.username()

u''

>>> form.username(style='width:200px;',class_='bar')

u''

class是pyhton的保留字,我们使用class_来代替class,渲染后的会获得正确的class属性,在模板中调用时则可以直接使用class。

 

通过上面的方法也可以修改id和name属性,但表单被提交后,WTForms需要通过name属性来获取对应的数据,所以不能修改name属性值。

​​​​​​​在模板中渲染表单

为了能够在模板中渲染表单,我们需要把表单类实例传入模板。首先在视图函数中实例化表单类LoginForm,然后在render_template()函数中使用关键字参数form将表单类实例传入模板,例如form/app.py

flask-wtf默认为每个表单启用CSRF保护,它为我们自动生成和验证CSRF令牌。默认情况下,flask-wtf使用程序密钥来对CSRF令牌进行签名(token),所以我们需要为程序设置密钥:app.secret_key = "secret key"

app.py:

# encoding=utf-8
from flask import Flask, render_template
from form import LoginForm
import os

app = Flask(__name__)
app.secret_key = os.getenv("SECRET_KEY", 'KSH')


@app.route("/form")
def basic():
    form = LoginForm()
    return render_template("baseForm.html", form=form)


if __name__ == "__main__":
    app.run(debug=True)

在templates目录下新建baseForm.html文件,内容如下:




    
    Title


    {{ form.csrf_token }}     {{ form.username.label }}{{ form.username }}
    {{ form.password.label }}{{ form.password }}
    {{ form.remember }}{{ form.remember.label }}
    {{ form.submit }}

需要注意的是,在上面的代码中,除了渲染各个字段的标签和字段本身,还调用了form.csrf_token属性渲染Flask_WTF为表单类自动创建的CSRF令牌字段。form.csrf_token字段包含了字段生成的CSRF令牌值,在提交表单后会自动被验证,为了确保表单通过验证,我们必须在表单中手动渲染这个字段(后面处理表单数据时验证)。

浏览器访问:http://127.0.0.1:5000/form

flask(十一):表单(一)_第6张图片

 

flask_WTF为表单类实例提供了一个form.hidden_tag()方法,这个方法会依次渲染表单中所有隐藏的字段。以为你csrf_token字段也是隐藏字段,所以当这个方法被调用时也会渲染csrf_token字段。渲染后获得的实际HTML代码如下:

flask(十一):表单(一)_第7张图片

 

在前面介绍过,使用render_kw字典或在调用字段时传入参数来定义字段的额外HTML属性,可以通过这种方式添加CSS类,我们编写一个Bootstrap风格的表单:

templates/bootstrap.html:

{% extends "base.html" %}
{% block styles %}
    
{% endblock %}

{% block content %}
    

Bootstrap Style Form

    
        {{ form.csrf_token }}         
            {{ form.username.label }}             {{ form.username(class='form-control') }}         
        
            {{ form.password.label }}             {{ form.password(class="form-control") }}         
        
            {{ form.remember(class="form-check-input") }}             {{ form.remember.label }}         
        {{ form.submit(class='btn btn-primary') }}     
{% endblock %}

app.py:

# encoding=utf-8
from flask import Flask, render_template
from form import LoginForm
import os

app = Flask(__name__)
app.secret_key = os.getenv("SECRET_KEY", 'KSH')


@app.route("/form")
def basic():
    form = LoginForm()
    return render_template("baseForm.html", form=form)


@app.route("/bootstrap")
def bootstrap():
    form = LoginForm()
    return render_template("bootstrap.html", form=form)


@app.route("/index")
def index():
    return "hello flask"

if __name__ == "__main__":
    app.run(debug=True)

form.py:

# -*- coding: utf-8 -*-#
from flask_wtf import FlaskForm
from wtforms import Form, StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length


class LoginForm(FlaskForm):
    username = StringField("Username", render_kw={"placeholder":"Your Username"},validators=[DataRequired()])
    # username = StringField("Username", validators=[DataRequired()])
    password = PasswordField("Password", validators=[DataRequired(), Length(8, 128)])
    remember = BooleanField("Remember me")
    submit = SubmitField("Log in")

浏览器访问:http://127.0.0.1:5000/bootstrap

flask(十一):表单(一)_第8张图片

 

如果想手动编写HTML表单的代码,需要注意表单字段的name属性值必须和表单来的字段名称相同,这样在提交表单时WTForms才能正确的获取数据并进行验证。

你可能感兴趣的:(flask)