wtforms

简介

WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。

安装:

?
1
pip3 install wtforms

用户登录注册示例

1. 用户登录

当用户登录时候,需要对用户提交的用户名和密码进行多种格式校验。如:

用户不能为空;用户长度必须大于6;

密码不能为空;密码长度必须大于12;密码必须包含 字母、数字、特殊字符等(自定义正则);

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgetsapp = Flask(__name__, template_folder='templates')
app.debug = Trueclass LoginForm(Form):name = simple.StringField(label='用户名',validators=[validators.DataRequired(message='用户名不能为空.'),validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')],widget=widgets.TextInput(),render_kw={'class': 'form-control'})pwd = simple.PasswordField(label='密码',validators=[validators.DataRequired(message='密码不能为空.'),validators.Length(min=8, message='用户名长度必须大于%(min)d'),validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')],widget=widgets.PasswordInput(),render_kw={'class': 'form-control'})@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'GET':form = LoginForm()return render_template('login.html', form=form)else:form = LoginForm(formdata=request.form)if form.validate():print('用户提交数据通过格式验证,提交的值为:', form.data)else:print(form.errors)return render_template('login.html', form=form)if __name__ == '__main__':app.run()

app.py

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>登录</h1>
<form method="post"><!--<input type="text" name="name">--><p>{{form.name.label}} {{form.name}} {{form.name.errors[0] }}</p><!--<input type="password" name="pwd">--><p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p><input type="submit" value="提交">
</form>
</body>
</html>

login.html

2. 用户注册

注册页面需要让用户输入:用户名、密码、密码重复、性别、爱好等。

from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgetsapp = Flask(__name__, template_folder='templates')
app.debug = Trueclass RegisterForm(Form):name = simple.StringField(label='用户名',validators=[validators.DataRequired()],widget=widgets.TextInput(),render_kw={'class': 'form-control'},default='alex')pwd = simple.PasswordField(label='密码',validators=[validators.DataRequired(message='密码不能为空.')],widget=widgets.PasswordInput(),render_kw={'class': 'form-control'})pwd_confirm = simple.PasswordField(label='重复密码',validators=[validators.DataRequired(message='重复密码不能为空.'),validators.EqualTo('pwd', message="两次密码输入不一致")],widget=widgets.PasswordInput(),render_kw={'class': 'form-control'})email = html5.EmailField(label='邮箱',validators=[validators.DataRequired(message='邮箱不能为空.'),validators.Email(message='邮箱格式错误')],widget=widgets.TextInput(input_type='email'),render_kw={'class': 'form-control'})gender = core.RadioField(label='性别',choices=((1, '男'),(2, '女'),),coerce=int)city = core.SelectField(label='城市',choices=(('bj', '北京'),('sh', '上海'),))hobby = core.SelectMultipleField(label='爱好',choices=((1, '篮球'),(2, '足球'),),coerce=int)favor = core.SelectMultipleField(label='喜好',choices=((1, '篮球'),(2, '足球'),),widget=widgets.ListWidget(prefix_label=False),option_widget=widgets.CheckboxInput(),coerce=int,default=[1, 2])def __init__(self, *args, **kwargs):super(RegisterForm, self).__init__(*args, **kwargs)self.favor.choices = ((1, '篮球'), (2, '足球'), (3, '羽毛球'))def validate_pwd_confirm(self, field):"""自定义pwd_confirm字段规则,例:与pwd字段是否一致:param field: :return: """# 最开始初始化时,self.data中已经有所有的值if field.data != self.data['pwd']:# raise validators.ValidationError("密码不一致") # 继续后续验证raise validators.StopValidation("密码不一致")  # 不再继续后续验证
@app.route('/register', methods=['GET', 'POST'])
def register():if request.method == 'GET':form = RegisterForm(data={'gender': 1})return render_template('register.html', form=form)else:form = RegisterForm(formdata=request.form)if form.validate():print('用户提交数据通过格式验证,提交的值为:', form.data)else:print(form.errors)return render_template('register.html', form=form)if __name__ == '__main__':app.run()

app.py

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>用户注册</h1>
<form method="post" novalidate style="padding:0  50px">{% for item in form %}<p>{{item.label}}: {{item}} {{item.errors[0] }}</p>{% endfor %}<input type="submit" value="提交">
</form>
</body>
</html>

register.html

3. 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 md5app = Flask(__name__, template_folder='templates')
app.debug = Trueclass MyCSRF(CSRF):"""Generate a CSRF token based on the user's IP. I am probably not verysecure, so don't use me."""def setup_form(self, form):self.csrf_context = form.meta.csrf_context()self.csrf_secret = form.meta.csrf_secretreturn super(MyCSRF, self).setup_form(form)def generate_csrf_token(self, csrf_token):gid = self.csrf_secret + self.csrf_contexttoken = md5(gid.encode('utf-8')).hexdigest()return tokendef 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标签namecsrf_field_name = 'csrf_token'# 自动生成标签的值,加密用的csrf_secretcsrf_secret = 'xxxxxx'# 自动生成标签的值,加密用的csrf_contextcsrf_context = lambda x: request.url# 生成和比较csrf标签csrf_class = MyCSRF# -- i18n# 是否支持本地化# locales = Falselocales = ('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()

View Code

其他:

1. metaclass

class MyType(type):def __init__(self, *args, **kwargs):print('MyType创建类',self)super(MyType, self).__init__(*args, **kwargs)def __call__(self, *args, **kwargs):obj = super(MyType, self).__call__(*args, **kwargs)print('类创建对象', self, obj)return objclass Foo(object,metaclass=MyType):user = 'wupeiqi'age = 18obj = Foo()

示例一

class MyType(type):def __init__(self, *args, **kwargs):super(MyType, self).__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):v = dir(cls)obj = super(MyType, cls).__call__(*args, **kwargs)return objclass Foo(MyType('MyType', (object,), {})):user = 'wupeiqi'age = 18obj = Foo()

示例二

class MyType(type):def __init__(self, *args, **kwargs):super(MyType, self).__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):v = dir(cls)obj = super(MyType, cls).__call__(*args, **kwargs)return objdef with_metaclass(arg,base):return MyType('MyType', (base,), {})class Foo(with_metaclass(MyType,object)):user = 'wupeiqi'age = 18obj = Foo()

示例三

2. 实例化流程分析

    # 源码流程1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中; meta类读取到cls._wtforms_meta中2. 执行构造方法a. 循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值添加到 self._fields[name] 中。即:_fields = {name: wtforms.fields.core.StringField(),}PS:由于字段中的__new__方法,实例化时:name = simple.StringField(label='用户名'),创建的是UnboundField(cls, *args, **kwargs),当执行完bind之后,才变成执行 wtforms.fields.core.StringField()b. 循环_fields,为对象设置属性for name, field in iteritems(self._fields):# Set all the fields to attributes so that they obscure the class# attributes with the same names.
                setattr(self, name, field)c. 执行process,为字段设置默认值:self.process(formdata, obj, data=data, **kwargs)优先级:obj,data,formdata;再循环执行每个字段的process方法,为每个字段设置值:for name, field, in iteritems(self._fields):if obj is not None and hasattr(obj, name):field.process(formdata, getattr(obj, name))elif name in kwargs:field.process(formdata, kwargs[name])else:field.process(formdata)执行每个字段的process方法,为字段的data和字段的raw_data赋值def process(self, formdata, data=unset_value):self.process_errors = []if data is unset_value:try:data = self.default()except TypeError:data = self.defaultself.object_data = datatry:self.process_data(data)except ValueError as e:self.process_errors.append(e.args[0])if formdata:try:if self.name in formdata:self.raw_data = formdata.getlist(self.name)else:self.raw_data = []self.process_formdata(self.raw_data)except ValueError as e:self.process_errors.append(e.args[0])try:for filter in self.filters:self.data = filter(self.data)except ValueError as e:self.process_errors.append(e.args[0])d. 页面上执行print(form.name) 时,打印标签因为执行了:字段的 __str__ 方法字符的 __call__ 方法self.meta.render_field(self, kwargs)def render_field(self, field, render_kw):other_kw = getattr(field, 'render_kw', None)if other_kw is not None:render_kw = dict(other_kw, **render_kw)return field.widget(field, **render_kw)执行字段的插件对象的 __call__ 方法,返回标签字符串

View Code

3. 验证流程分析

        a. 执行form的validate方法,获取钩子方法def validate(self):extra = {}for name in self._fields:inline = getattr(self.__class__, 'validate_%s' % name, None)if inline is not None:extra[name] = [inline]return super(Form, self).validate(extra)b. 循环每一个字段,执行字段的 validate 方法进行校验(参数传递了钩子函数)def validate(self, extra_validators=None):self._errors = Nonesuccess = Truefor name, field in iteritems(self._fields):if extra_validators is not None and name in extra_validators:extra = extra_validators[name]else:extra = tuple()if not field.validate(self, extra):success = Falsereturn successc. 每个字段进行验证时候字段的pre_validate 【预留的扩展】字段的_run_validation_chain,对正则和字段的钩子函数进行校验字段的post_validate【预留的扩展】

View Code

作者:武沛齐
出处:http://www.cnblogs.com/wupeiqi/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

转载于:https://www.cnblogs.com/l-jie-n/p/10092576.html

Flask wtforms相关推荐

  1. flask WTForms

    WTForms由三个主要部分组成:字段,检验器和表单 字段代表输入域,做初步的检查 检验器是附加在字段上的函数,确保表单中的数据符合要求 表单是python类,包含了字段和检验器 表单 描述 Date ...

  2. Flask开发微电影网站(一)

    1.用到的Flask知识 1.使用整形,浮点型,路径型,字符串型下正则表达式路由转化器 2.使用GET与POST请求,上传文件,cookie获取与响应,404处理 3.使用模板自动转义,定义过滤器,定 ...

  3. Flask项目之个性化微电影网站的实战开发(一)

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 项目源码下载 目录 一丶叙述 二丶Windows环境搭建 三丶项目分析丶搭建目录以及模型设计 四丶搭建前台页面 一丶叙述 1.项目 ...

  4. python视频网站项目_[项目实战] Python Flask构建微电影视频网站

    注:本站源码仅做学术研究,自娱自乐使用,不得用于任何的非法商业用途 由于版权原因.本站将无限期停止微擎模块资源下载如果有任何侵犯您权益的内容请联系小站删除哦.小站一定会积极配合的. 课程目录: (下载 ...

  5. python视频网站项目_Python超羽量级灵活框架 Flask实战微电影视频网站 大小项目通吃 Flask实战项目...

    课程名称: Python超羽量级灵活框架 Flask实战微电影视频网站 大小项目通吃 Flask实战项目视频教程 课程简介: Flask作为Python编写的Web小型框架,可以使用Python快速开 ...

  6. Python-Flask开发微电影网站(一)

    1.用到的Flask知识 1.使用整形,浮点型,路径型,字符串型下正则表达式路由转化器 2.使用GET与POST请求,上传文件,cookie获取与响应,404处理 3.使用模板自动转义,定义过滤器,定 ...

  7. python 开发视频播放网站_python开发微电影视频网站教程附源码

    做为一个合格的Pythoner,只掌握一个框架是不够,如果你有过其它Python框架(例如django)的使用经验,对比不同框架的特性来学习,你将收获更多 当前信息若含有黄赌毒等违法违规不良内容,请点 ...

  8. android反编译后有中文乱码,android反编译查看源码,apk解压后XML乱码解决

    详解MySQL的用户密码过期功能 这篇文章主要为大家详细介绍了MySQL的用户密码过期功能的相关资料,需要的朋友可以参考下   Payment Card Industry,即支付卡行业,PCI行业表示 ...

  9. (旧)3- Flask构建弹幕微电影网站- 课程介绍

    Flask 构建微电影视频网站 已上线演示地址: http://movie.mtianyan.cn 项目源码地址:https://github.com/mtianyan/movie_project 持 ...

最新文章

  1. 程序员必知的20个Python技巧
  2. matlab基本杆组-运动学仿真,MATLAB基本杆组-运动学仿真.pdf
  3. 如何自学python爬虫-怎样入门学习Python爬虫?
  4. 【控制】《多智能体系统一致性协同演化控制理论与技术》纪良浩老师-第4章-具有随机扰动的多智能体系统脉冲一致性
  5. iReport中求和的问题
  6. OpenCASCADE:Foundation Classes之插件管理
  7. ajax 传参数 java后台接收
  8. Mysql数据库(八)——mysql高阶语句(中)
  9. 2019最佳年会,新东方6名员工冒着离职的风险,在年会上怒怼老板
  10. P2522 [HAOI2011]Problem b
  11. 安卓camera总体框架
  12. gridview 默认编辑按钮改成图片
  13. 机器学习入门经典好文
  14. 《逻辑学导论》(第11版)学习(一)
  15. 卡巴斯基7.0反病毒一年激活码免费领取(官方活动,现已停止)
  16. 【Flutter系列】第一期——初识Dart语言
  17. 必修三计算机选修三知识点总结,高中生物必修一、必修二、必修三、选修三知识点总结(人教版).pdf...
  18. sem_init函数用法
  19. xbox360 corona hacked, RGH3成功破解corona
  20. mysql的时间最晚日期_MySQL日期时间函数

热门文章

  1. 第4章 同余问题《信息学奥赛一本通 提高篇》
  2. php node.js django,Vue.js和Django搭建前后端分离项目示例详解
  3. 表单元素聚焦状态回车提交表单问题小记
  4. c++ sort 从大到小排序_算法的艺术:MySQL order by对各种排序算法的巧用
  5. Qt工作笔记-MySQL获取select表头(域)数据
  6. Qt文档阅读笔记-QUdpSocket基本表述及简单实现
  7. 5.3稀疏矩阵的十字链表存储
  8. java8的时间工具类_JAVA8日期工具类
  9. 量子计算机超越传统计算机位数,量子计算机相对于传统的计算机有着怎样的优势?...
  10. mysql Windows导入sql 失败