Flask表单验证组件WTForms

一、安装

pip install wtforms

Flask 表单操作库 flask_WTF flask_WTForms
Flask 之 flask-SQLAlchemy 的使用
使用 WTForms 进行表单验证

1.1、wtforms源码执行流程

在这里插入图片描述

二、简单的使用

# 第一中使用方法
from wtforms import Form, BooleanField,TextField,PasswordField,validators
class RegistrationForm(Form): # 定义的 form 表单类必须继承 Form
	username = TextField('Username', [validators.Length(min=4, max=25)],default='123')
	email = TextField('Email Address', [validators.Length(min=6, max=35)])
	password = PasswordField('New Password', [
		validators.Required(),
		validators.EqualTo('confirm', message='Passwords must match')
	])
	confirm = PasswordField('Repeat Password')
	accept_tos = BooleanField('I accept the TOS', [validators.Required()])
# 第二种使用方法
from wtforms.fields import core # 核心功能
from wtforms.fields import html5 # html5标签
from wtforms.fields import simple # 简单使用
from wtforms import Form
from wtforms import validators
from wtforms import widgets
class RegistrationForm(Form):
	username = simple.StringField(
		label='用户名',
		validators=[
			Myvalidators(message="用户名必须是haiyan"),#也可以自定义正则
			validators.DataRequired(message="用户名不能为空"),
			validators.Length(max=8,min=3,message="用户名长度必须大于%(max)d且小于%(min)d")
		],
		widget=widgets.TextInput(),
		render_kw={'style':'font-size:12px;','class':'user'},
		default='123',
	)
	password = simple.PasswordField(
		label='密码',
		validators=[
			validators.DataRequired(message="密码不能为空"),
			validators.Length(max=8,min=3,message="密码长度必须大于%(max)d且小于%(min)d"),
			validators.Regexp(regex="\d+",message="密码必须是数字"),
		],
		widget=widgets.PasswordInput(),
		render_kw={'style':'font-size:12px;','class':'pass'},# 设置input 属性
		default='123', # 默认的value
	)
from flask import Flask,render_template as render,request
app = Flask(__name__)
@app.route('/index',methods=['GET'])
def index():
	if request.method == 'GET':
		form = RegistrationForm()
		return render('index.html',form=form)
	form = RegistrationForm(formdata=request.form)
	print(form.data) # {'username': '123', 'password': 'tang'} 获取表单提交的数据
	print(form.data['username']) # 123 获取表单提交的单个数据
	if form.validate(): # 必须调用验证方法,form.validate() 进行验证,不然是不会进行验证的
	    print('验证成功')
	else:
	    return render('index.html',form=form)
PS:
1、字段名是区分大小写的
2、字段名不能以'_'开头
3、字段名不能以'validate'开头

Form的主要属性:
data:字典类型,包括每一个字段的数据。如果需要频繁访问字段值,可以使用form.<field>.data进行访问
errors:字典类型,包括每一个字段的错误信息。

三、字段以及参数

3.1、基本字段名称和含义

字段名 字段含义
StringField 文本字段
TextAreaField 多行文本字段
PasswordField 密码文本字段
HiddenField 隐藏文本字段
DateField 文本字段,值为datetime.date 格式
DateTimeField 文本字段,值为datetime.datetime 格式
IntegerField 文本字段,值为整数
DecimalField 文本字段,值为decimal.Decimal
FloatField 文本字段,值为浮点数
BooleanField 复 选 框,值为True 和False
RadioField 一组单选框
SelectField 下拉列表 参数:choices=[(1,‘one’),(2,‘two’)]
SelectMultipleField 下拉列表,可选择多个值
FileField 文件上传字段
SubmitField 表单提交按钮
FormField 把表单作为字段嵌入另一个表单
FieldList 一组指定类型的字段

3.2、基本字段的使用方法

3.2.1、StringField

# <input class="form-control" id="input_title" name="title" placeholder="请输入片名!" type="text" value="">
title = StringField(
    label='片名',
    validators=[
        DataRequired('请输入片名!')
    ],
    description='片名',
    render_kw={
        'class': 'form-control',
        'id':'input_title',
        'placeholder':'请输入片名!',
        'required':False
    }
)

3.2.2、FileField

# <input id="input_url" name="url" required="" type="file">
url = FileField(
    label='文件',
    validators=[
      DataRequired('添加影片!')
    ],
    description='文件',
    render_kw={
        'id':'input_url'
    }
)

3.2.3、TextAreaField

# <textarea class="form-control" id="info" name="info" required="" rows="10" style="resize:none;"></textarea>
info = TextAreaField(
    label='介绍',
    validators=[
        DataRequired('请输入简介!')
    ],
    description='介绍',
    render_kw={
        'class':'form-control',
        'rows':'10',
        'style':'resize:none;'
    }
)

3.2.4、SelectField

'''
<select class="form-control" id="input_star">
    <option value="1">1星</option>
    <option value="2">2星</option>
    <option value="3">3星</option>
    <option value="4">4星</option>
    <option value="5">5星</option>
</select>
'''
star = SelectField(
    label='星级',
    description='星级',
    render_kw={
        'class':'form-control',
        'id':'input_star',
    },
    choices = [(1,'1星'),(2,'2星'),(3,'3星'),(4,'4星'),(5,'5星')],
    default=1,
    coerce=int
)

四、模版中的表单

'''
以下是一个使用宏的示例
_formhelpers.html模板:
'''
{% macro render_field(field) %}
  <dt>{{ field.label }}</dt>
  <dd>
  	  {{ field(**kwargs)|safe }}
	  {% if field.errors %}
	    <ul class="errors">
	    {% for error in field.errors %}
	      <li>{{ error }}</li>
	    {% endfor %}
	    </ul>
	  {% endif %}
  </dd>
{% endmacro %}

以下是使用了上面的 _formhelpers.html 的 register.html 模板:

{% from "_formhelpers.html" import render_field %}
<form method="post" action="/register">
  <dl>
    {{ render_field(form.username) }}
    {{ render_field(form.email) }}
    {{ render_field(form.password) }}
    {{ render_field(form.confirm) }}
    {{ render_field(form.accept_tos) }}
    '''
    	显示名称:input框
   	{{ form.password.label }}:{{ form.password }} {{ form.errors.password }}
    	{% for i in form %}
    		{{ i.label }}:{{ i }}
    	{% endfor %}
    '''
  </dl>
  <p><input type="submit" value="Register"></p>
</form>

五、验证器validators

5.1、form表单类中的声明,以列表形式展现[]:

validators.DataRequired(‘错误提示’) 必填限制 
validators.Length(min=4,max=8,message=’错误提示’) 长度限制 
validators.Email(‘错误提示’) 邮箱验证 
validators.EqualTo(‘字段名’,’错误提示’)
username = StringField('用户名',[validator.DataRequired('用户名必填')])
password = IntegerField('密码',[validator.DataRequired('密码必填')])
userlevel = SelectField('用户权限',[validator.DataRequired('用户权限必填')])

5.2、常用的 Validators 属性

校验器 作用
Required 必填校验器,要求字段必须有值
Requiredstring 必填字符串校验器,要求必须有值且长度大于0,即不能是空字符串。默认会去掉字符串前后空格
参数fieldName:该参数指定校验的字段名称,如果是字段校验,则不用指定该参数
参数trim:该参数为 可选参数,用于指定是否在校验之前对字符串进行整理。
Stringlength 字符串长度校验器,用于检验字段中字符串长度是否在指定的范围
参数 maxLength:用于指定最大字符串长度,该参数为 可选
参数 minLength:用于指定最小字符串长度,该参数为 可选
Int 整数校验器,可以配置整数在指定的范围内
参数 min:指定字段值的最小值,该参数为 可选
参数 max:指定字段值的最大值,该参数为 可选
Date 日期校验器,可以配置日期在指定的范围内
参数 min:指定字段日期值的最小值,该参数为 可选
参数 max:指定字段日期值的最大值,该参数为 可选
Email 邮件地址校验器,要求被检查的字段如果非空,则必须是合法的邮件地址。
Regex 检查是否能匹配到正则表达式,参数为regex
EqualTo 比较两个字段的值;常用于要求输入两次密码进行确认的情况
IPAddress 验证IPv4 网络地址
Length 验证输入字符串的长度
NumberRange 验证输入的值在数字范围内
Optional 无输入值时跳过其他验证函数
URL 验证URL
AnyOf 确保输入值在可选值列表中
NoneOf 确保输入值不在可选值列表中

5.3、自定义form标签

from wtforms.widgets import HTMLString, html_params
from wtforms import Field
class ButtonWidget(object): #自定义一个input组件
	def __call__(self,field,**kwargs):
		if field.name is not None:
			kwargs.setdefault("name",field.name)			
			kwargs.setdefault("type",field.btype)
			kwargs.setdefault('id',field.id)
			kwargs.setdefault("value",field.value)
			return HTMLString("<input %s>"%(html_params(**kwargs)))
class InputButtonField(Field):
	widget = ButtonWidget()
	"""
	@params value 按钮的标签
	@params text  按钮的文本
	"""
	def __init__(self,value="按钮",text="btn",btype="button",**kwargs):
		super(InputButtonField, self).__init__(**kwargs)
		self.type = "SubmitField"
		self.btype = btype
		self.value = value
		self.text = text

六、Meta 的理解

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect, session
from wtforms import Form
from wtforms.csrf.core import CSRF
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets
from hashlib import md5

app = Flask(__name__, template_folder='templates')
app.debug = True


class MyCSRF(CSRF):
    """
    Generate a CSRF token based on the user's IP. I am probably not very
    secure, so don't use me.
    """

    def setup_form(self, form):
        self.csrf_context = form.meta.csrf_context()
        self.csrf_secret = form.meta.csrf_secret
        return super(MyCSRF, self).setup_form(form)

    def generate_csrf_token(self, csrf_token):
        gid = self.csrf_secret + self.csrf_context
        token = md5(gid.encode('utf-8')).hexdigest()
        return token

    def validate_csrf_token(self, form, field):
        print(field.data, field.current_token)
        if field.data != field.current_token:
            raise ValueError('Invalid CSRF')


class TestForm(Form):
    name = html5.EmailField(label='用户名')
    pwd = simple.StringField(label='密码')

    class Meta:
        # -- CSRF
        # 是否自动生成CSRF标签
        csrf = True
        # 生成CSRF标签name
        csrf_field_name = 'csrf_token'

        # 自动生成标签的值,加密用的csrf_secret
        csrf_secret = 'xxxxxx'
        # 自动生成标签的值,加密用的csrf_context
        csrf_context = lambda x: request.url
        # 生成和比较csrf标签
        csrf_class = MyCSRF

        # -- i18n
        # 是否支持本地化
        # locales = False
        locales = ('zh', 'en')
        # 是否对本地化进行缓存
        cache_translations = True
        # 保存本地化缓存信息的字段
        translations_cache = {}


@app.route('/index/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        form = TestForm()
    else:
        form = TestForm(formdata=request.form)
        if form.validate():
            print(form)
    return render_template('index.html', form=form)


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

七、钩子函数

在input组件类中创建以“validate_”开头的函数,在其实现对form提交数据的处理。

class ButtonWidget(object):# input组件类
 def validate_name(self,field): # 钩子函数必须以validate_开头
   print(field.date)
发布了126 篇原创文章 · 获赞 64 · 访问量 6万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览