Flask(WTF)表单操作

袁开宇
2023-12-01

Flask表单简介

Form表单,在Web应用中无处不在。比如:用户登录表单,用户注册表单。

  • 所有的表单都有共性,比如有文字输入框,单选框,密码输入框等;
  • 表单的验证也有共性,比如有非空验证,长度限制,类型验证等。

如果有个框架能够将这些共性抽象出来,那就能大量简化我们的工作。Python的WTForms就提供了这些功能。这里我们就结合Flask的WTForms扩展。Flask-WTF,来介绍如何在Web应用中制作表单。

安装和启用:

pip install Flask-WTF

一个简单的表单

表单文件

WTForms让我们在后端代码中定义表单类,并列出表单的字段和相应的验证规则。下面是定义的一个MyForm类:

from flask_wtf import Form
from wtforms import StringField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
   email = StringField(u'邮箱', validators=[
               DataRequired(message= u'邮箱不能为空'), Length(1, 64),
               Email(message= u'请输入有效的邮箱地址,比如:username@domain.com')])
   password = PasswordField(u'密码',
                 validators=[Required(message= u'密码不能为空')])
   submit = SubmitField(u'登录')

常见的表单域类型

表单域类型描述
StringField文本框
TextAreaField多行文本框
PasswordField密码输入框
HiddenField隐藏文本框
DateField接收给定格式datetime.date型的文本框
DateTimeField接收给定格式datetime.datetime型的文本框
IntegerField接收整型的文本框
DecimalField接收decimal.Decimal型的文本框
FloadField接收浮点型的文本框
BooleanField带有True和False的复选框
RadioField一组单选框
SelectField下拉选择框
SelectMultipleField下拉多选框
FileField文本上传框
SubmitField表单提交按钮
FormField将一个表单作为表单域嵌入到容器表单中
FieldList给定类型的表单域列表

常见验证规则

验证规则说明
DataRequired验证必填项
Email验证邮件地址格式
EqualTo验证必须同另一个字段值相同,它需要传入另一个字段的名称“fieldname”
Length验证输入字符串长度,它有两个参数:min最小长度,max最大长度,缺省的话就不检查
NumberRange验证输入数值的范围,它有两个参数:min最小长度,max最大长度,缺省的话就不检查
URL验证URL格式
IPAddress验证IP地址格式,默认IPV4,你可以传入‘ipv6=True’来验证IPV6地址
MacAddress验证Mac地址格式
AnyOf传入一个列表作为参数,验证是否匹配类表中的任一值
NoneOf传入一个列表作为参数,验证是否与列表中的所有值都不同
Regexp正则表达式验证,需传入一个正则表达式,它还有一个flags参数,如果你传入‘re.IGNORECASE’,就会忽略大小写

视图函数文件

@app.route('/login/', methods=['GET', 'POST'])
def login():
   form = LoginForm()
   if form.validate_on_submit():
       email = form.email.data
     
...
   return render_template('login.html', form=form)

验证数据

点击了表单上的提交按钮时,form.validate_on_submit()判断会做下面两件事情:

  • 通过is_submitted()判断是否以POST方法提交了表单
  • 通过WTForms提供的validate()来验证表单数据是否通过验证。
  • 当validate()验证未通过时,会在表单字段下面显示我们传进去的错误提示(例如:message=‘密码不能为空’)

自定义验证

也可以在表单类中创建自定义的验证函数,举个简单的例子;
自定义函数以validate_ + “要验证的属性名称”,比如要验证username,我们的自定义验证函数应为:validate_username

def validate_username(self, field):
   # field.data是用户输入的数据。
   if field.data == 'admin':
       # ValidationError从wtforms导入,用来向用户显示错误信息,
       # 验证函数的名称由validate_fieldname组成。
       raise ValidationError('超级管理员已被注册,换一个吧。')

我们也可以在这里对用户数据进行预处理:
如果网址不是http开头,就转为http网址:

# 这个函数对用户输入的网址进行处理(字段名为website)。
def validate_website(self, field):
   if field.data[:4] != "http":
       field.data = "http://" + field.data

获取数据

验证通过之后:

  • 使用form.email.data来获得数据,

form.email.data

  • WTForms提供的静态方法.data返回一个以字段名(field name)和字段值(field value)作为键值对的字典:

form.data[‘email’]

前端文件

  • form.hidden_tag()会生成一个隐藏的标签,其中会渲染任何隐藏的字段,最主要的是CSRF字段。
  • CSRF(Cross-Site Request Forgery跨站请求伪造)是一种通过伪装来自受信任用户的请求,来发送恶意攻击的方法,WTForms默认开启CSRF保护。
<form method="POST" action="/login/">
  {{ form.hidden_tag() }}
  {{ form.user.label }}: {{ form.user(size=20) }}
   <input type="submit" value="Submit">
</form>

Flask-WTF表单处理实际应用案例:

主程序app.py


from flask import Flask, render_template, flash

from forms import LoginForm,RegisterForm
from flask_bootstrap import Bootstrap

app = Flask(__name__)
# 设置配置
app.config.from_pyfile('config.py')
# 实例化bootstrap对象
bootstrap = Bootstrap(app)

@app.route('/login/',methods=['GET','POST'])
def login():
    # 实例化表单对象
    form = LoginForm()
    # 1). 判断是否为post方法提交数据
    # 2). 是否通过验证函数
    if form.validate_on_submit():
        # 获取表单数据(内容)
        email = form.email.data
        password = form.password.data
        if email == 'westos@qq.com' and password == 'westos':
            flash("登录成功")
            return '登录成功'
        else:
            # flash('登录失败')
            # return render_template('login.html')
            return '登录失败'
    else:
        # 将form表单传递给html,按照表单的规则进行验证
        return render_template('bs_login.html',form=form)

@app.route('/register/',methods=['GET','POST'])
def register():
    form = RegisterForm()

    if form.validate_on_submit():
        return '获取性别%s' %(form.gender.data)
    else:
        return render_template('register.html',form=form)
# def register():
#         return '注册'

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

if __name__ == '__main__':
    app.run()


配置文件config.py

SECRET_KEY = 'WESTOS'

表单文件forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, SelectField, RadioField
from wtforms.validators import DataRequired, Email, Length, EqualTo, Regexp, ValidationError


class LoginForm(FlaskForm):
    email = StringField(label='电子邮箱',
                        validators=[
                            DataRequired(message='邮箱不能为空'),
                            Length(1,15, message='长度不符合条件'),
                            Email(message='请输入有效的邮箱地址,比如username@domain.com')
                        ])
    password = PasswordField(label='密码',
                             validators=[
                                 DataRequired(message='密码不能为空')])
    submit = SubmitField('登录')

class RegisterForm(FlaskForm):
    name = StringField(
        label='用户名',
        validators=[DataRequired(message='用户名不能为空'),
                    Length(5,12,message='用户名长度必须在5-12之间')]
    )
    password = PasswordField(
        label='密码',
        validators=[DataRequired(),
                    Length(6,16,message='密码格式不正确')]
    )

    repassword = PasswordField(
        label='确认密码',
        validators=[DataRequired(),
                    # 验证当前表单输入密码和password表单输入密码是否一致,如果不一致,报错
                    EqualTo('password',message='密码不一致')]
    )
    email = StringField(
        label='邮箱',
        validators=[
            DataRequired(),
            Email(message='邮箱格式错误')
        ]
    )
    phone = StringField(
        label='电话号码',
        validators=[
            DataRequired(),
            Regexp(r'1\d{10}',message='电话号码格式错误')
        ]
    )
    # 下拉单选框
    gender = SelectField(
        label='性别',
        # 填写的信息传入后台的类型
        coerce=int,
        # 下拉列表的选项
        choices=[(1,'男'),(2,'女')]
    )
    # # 下拉多选框
    tech = SelectMultipleField(
        label='擅长领域',
        coerce=int,
        choices=[(1,'python'),(2,'linux'),(3,'php'),(4,'java')]
    )
    def validate_name(self,field):
        # field.data是用户输入的数据
        if field.data == 'admin':
            # ValidationError用来向用户显示错误信息
            # 验证的函数的名称由validate_fieldname组成
            raise ValidationError('超级管理员已经被注册,换一个吧')
    submit = SubmitField(label='注册')


login页面:login.html
通过form表单格式编写页面,代码简洁明了:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{% for message in get_flashed_messages() %}
<p style="color: red">{{ message }}</p>
{% endfor %}

<form action='/login/' method="POST">
{#    <input type="email" name="email" placeholder="email"><br>#}
{#    <input type="password" name="password" placeholder="password"><br>#}
{#    <input type="submit" value="登录">#}
    {#    显示报错信息#}
    {#    {{ form.email.errors }} #}
    {{ form.hidden_tag() }}
    {{ form.email.label }}{{ form.email()}}{{ form.email.errors }}
    {{ form.password.label }}{{ form.password() }}{{ form.password.errors }}
    {{ form.submit() }}
</form>

</body>
</html>

注册页面register.html
通过wtf.quick_form(form)快速实现页面:

{#导入bootstrap的基模板,自动加载css样式和js动效#}
{% extends "bootstrap/base.html" %}
{#导入html代码,并起别名#}
{% import "bootstrap/wtf.html" as wtf  %}

{% block title %}

    注册
{% endblock %}

{% block content %}
    <div style="width:70%; margin: 0 auto">

        <h1>用户注册</h1>
        <hr/>
{#        传入表单对象#}
        {{ wtf.quick_form(form) }}

    </div>
{% endblock %}


详细代码可以:点击这里,包含css,js静态文档和其余html页面。

 类似资料: