Flask-8 flask-wtf的使用(灵活的表单验证)

介绍:

Flask-WTF 提供了简单地 WTForms 的集成。

WTForms是一个灵活的表单验证和渲染库,用于Python
Web开发。它可以与您选择的任何Web框架和模板引擎一起使用。它支持数据验证、CSRF 保护、国际化 (I18N)
等。有各种社区库提供了与流行框架的更紧密集成。

为什么要用WTF,WT Forms是用于提供用户界面的灵活的表单呈现和验证库

WTForms文档:https://wtforms.readthedocs.io/en/3.0.x/
Flask-WTF文档:http://www.pythondoc.com/flask-wtf/


用 pip 安装 Flask-WTF 是十分简单的:

pip install Flask-WTF
# 下载的内容会包含wtforms包

该模块包含一个Form类, 该类被视为所有与表单相关的操作的父类。

一、具体实现案例:

1、创建表单类

内容:主要为页面输入中各种规则的显示

"""
@File: formtest.py
"""
import re
from flask_wtf import FlaskForm
from flask_wtf.file import FileRequired, FileField, FileAllowed
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length, ValidationError, EqualTo
"""
从 0.9.0 版本开始,Flask-WTF 将不会从 wtforms 中导入任何的内容.
用户必须自己从 wtforms 中导入字段。
"""

class UserForm(FlaskForm):
    name = StringField(label='用户名',
                       validators=[DataRequired(),  
                       # validators:验证器
                                   Length(min=6,max=12,
                                    	message='用户名长度必须在6到12位之间')
                                   ]
                       )
    phone = StringField(label='手机号码',
                        validators=[DataRequired(),
                                    Length(min=11, max=11, 
                                    message='手机号码必须是11位数字')
                                    ]
                        )
    password = PasswordField(label='密码',
                             validators=[DataRequired(),
                                         Length(min=6, max=12,
                                         message='密码长度必须在6到12位之间')
                                         ]
                             )

    repassword = PasswordField(label='确认密码',
                               validators=[DataRequired(),
                                           Length(min=6, max=12, 
                                           message='密码长度必须在6到12位之间'),
                                           EqualTo('password', '两次密码不一致')
                                           ]
                               )
    user_img = FileField(label='用户头像',
                         validators=[FileRequired(),
                                     FileAllowed(['jpg', 'png', 'jpeg'],
                                     message='用户头像必须是图片格式')
                                     ]
                         )
    def validate_name(self, data):  
    	# 自定义表单验证
    	# 重写了方法 validate_on_submit--继承->> self.validate()--继承->> validate()
    	# 可查看下面的截图
        
        print('---->>>', self.name.data, '==', data.dta)
        if self.name.data[0].isdigit():
            raise ValidationError('用户名不能以数字开头')

    def validate_phone(self, data):
        """校验手机号"""
        phone = data.data
        if not re.search(r'^1[35678]\d{9}', phone):  
        # search返回内容是None或re.Match object
            raise ValidationError('手机号码格式错误!')

FlaskForm类中的源码部分
在这里插入图片描述
在这里插入图片描述
Form对象调用validate函数时会自动寻找validate_{name}的方法添加到验证序列,并在原先字段的验证序列验证完毕后执行。

2、视图中使用

这里涉及到了CSRF保护,可查看后面文章

"""
@File: app.py
"""

import os
from flask import Flask, render_template, make_response
from flask_wtf import CSRFProtect
from werkzeug.utils import secure_filename
from formtest import UserForm # 导入表单类

app = Flask(__name__)

# 必须要设置SECRET_KEY这个配置项
# 需要为CSRF保护设置一个密钥,通常情况下,和Flask应用的SECRET_KEY是一样的。
app.config['SECRET_KEY'] = 'hsdkfhksd'

app.config['ENV'] = 'development'

# 全局使用CSRF保护,为了能够让所有的视图受到CSRF保护,需要扩展 CsrfProtect模块
csrf = CSRFProtect(app=app)


@app.route('/home', methods=['GET', 'POST'])
def home():
    uform = UserForm()
    if uform.validate_on_submit():
        """注意:
        	1、不需要把 request.form 传给 Flask-WTF;Flask-WTF 会自动加载。
         	2、validate_on_submit 将会检查是否是一个 POST 请求并且请求是否有效。
        """
        name = uform.name.data
        password = uform.password.data
        phone = uform.phone.data
        user_img = uform.user_img.data  # <FileStorage类型>
        filename = secure_filename(user_img.filename)  # 如果文件名是中文,会只显示后缀,不显示文件名,会有错误,尽量不用中文名

        BASE_DIR = os.path.dirname(os.path.abspath(__file__))
        STATIC_DIR = os.path.join(BASE_DIR, 'static')
        STATIC_DIR = os.path.join(STATIC_DIR, 'upload')

        user_img.save(os.path.join(STATIC_DIR, filename))
        return '这是一个post请求,提交成功'

    return render_template('user.html', uform=uform)

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

CSRF跨站请求伪造,源于WEB的隐式身份验证机制,WEB的身份验证机制虽然可以保证一个请求来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的。

如果网站没有通过CSRF验证,都会返回400响应

3、模版中的使用
<!-- user.html -->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户页面</title>

    <style>
        p span {
            color: red;
            font-size: 14px;
        }
    </style>

</head>
<body>
<form action="{{ url_for('home') }}" method="post" enctype="multipart/form-data">
    <p>{{ uform.csrf_token }}</p>  <!--可在控制台中可查看CSRF令牌, 没有这个会报400-->
    <p>{{ uform.hidden_tag() }}</p>

    <!--输入用户名-->
    <p>{{ uform.name.label }}: {{ uform.name }}
        <span>{% if uform.name.errors %} {{ uform.name.errors.0 }} {% endif %} </span>
    	<!-- 自定义表单报的错 def validate_name(): ...... -->
    </p>

    <!--输入密码-->
    <p>{{ uform.password.label }}: {{ uform.password }}
        <span>{% if uform.password.errors %} {{ uform.password.errors.0 }} {% endif %} </span>
    </p>

    <!--输入确认密码-->
    <p>{{ uform.repassword.label }}: {{ uform.repassword }}
        <span>{% if uform.repassword.errors %}{{ uform.repassword.errors.0 }}{% endif %} </span>
    </p>

    <!--输入手机号-->
    <p>{{ uform.phone.label }}: {{ uform.phone }}
        <span>{% if uform.phone.errors %}{{ uform.phone.errors.0 }}{% endif %} </span>
    </p>

    <!--上传文件-->
    <p>{{ uform.user_img.label }}: {{ uform.user_img }}
        <span>{% if uform.user_img.errors %}{{ uform.user_img.errors.0 }}{% endif %} </span>
    </p>
    
    <p><input type="submit" value="提交"></p>
    
</form>
</body>
</html>
4、运行后访问查看提示

这里输入框还可以使用bootstrap美化下,这里就不写了…

  1. 这种是自定义的校验报错显示(def validate_name: …)
    在这里插入图片描述

  2. 这种是不符合验证器的提示 (validators)
    在这里插入图片描述

二、总结:

1、视图中使用:

from test import UserForm # 导入定义的类
def xxxx():
	uform = UserForm()
	......
	return render_template('user.html',uform=uform)

2、模板中使用:

<form action="/" method="post">
        {{ uform.csrf_token }}
        {{ uform.hidden_tag() }}
        {{ uform.name }} {{ uform.name.error.0 }}
        {{ uform.password }} {{ uform.password.error.0 }}
        <p><input type="submit" value="提交"></p>
    </form>

3、验证是否是一个POST,并且是否有效:validate_on_submit()

@app.route('/', methods=['GET','POST'])
def test():
	uform = UserForm()
	if uform.validate_on_submit():
		return '这是一个post请求'
	return render_template('user.html', uform=uform)

4、在自定义表单类中,还有其他Filed类型、和各种验证

4.1 各种Filed字段类型

class UserForm(FlaskForm):
    name = StringField(label='用户名',
                       validators=[DataRequired(),  # validators:验证器
                                   Length(min=6, max=12)
                                   ]
                       )
                       
__all__ = (
    "BooleanField",
    "TextAreaField",
    "StringField", #  name = StringField( ...... )
    "PasswordField",
    "FileField",
    "MultipleFileField",
    "HiddenField",
    "SearchField",
    "SubmitField",
    "TelField",
    "URLField",
    "EmailField",
)

4.2 各种的验证:

repassword = PasswordField(label='确认密码',
                           validators=[DataRequired(),
                                       Length(min=6, max=12),
                                       EqualTo('password', '两次密码不一致')
                                       ]
                           )

__all__ = (
    "DataRequired",
    "data_required",
    "Email",
    "email",
    "EqualTo", # EqualTo('password', '两次密码不一致')
    "equal_to",
    "IPAddress",
    "ip_address",
    "InputRequired",
    "input_required",
    "Length",
    "length",
    "NumberRange",
    "number_range",
    "Optional",
    "optional",
    "Regexp",
    "regexp",
    "URL",
    "url",
    "AnyOf",
    "any_of",
    "NoneOf",
    "none_of",
    "MacAddress",
    "mac_address",
    "UUID",
    "ValidationError",
    "StopValidation",
)
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值