首先我们来创建一个From类

from wtforms.form import Form
from wtforms import StringField
from wtforms.validators import DataRequired
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 = UnboundField(PasswordField, *args, **kwargs) creation_counter=2
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'} # 定义css样式
) class Meta:
csrf = False # 是否自动创建csrf def validate_pwd(self,*args,**kwargs):
""验证用户密码""
pass @app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html', form=form)
else:
form = LoginForm(formdata=request.form)
if form.validate():
print('用户提交数据通过格式验证,提交的值为:', form.name.data,form.pwd.data)
else:
print(form.errors)
return render_template('login.html', form=form)

 当代码运行起来之后我们可以看到这样的页面:

当我们看到这个页面的时候,我们是否想过后台到底发生了什么,为我们生成了这样的页面呢。接下来我们从Form模块的导入来分析:

首先从导入的Form,这个类是怎么定义的呢:

class Form(with_metaclass(FormMeta, BaseForm)):
pass

 一般我们看到的类的继承,都是写一个类,with_metaclass 应该是我们第一次见到,她到底作业什么呢?我们继续查看

def with_metaclass(meta, base=object):
# 通过meta创建一个类 并继承base,实际上是继承了两个类(meta,base)
return meta("NewBase", (base,), {})

当我们实例化From或From的派生类的时候就会调用FormMeta的,因为FormMeta继承了type并重写了__call__方法,对于类的执行顺序

  1. 元类的__init__方法
  2. 元类的__call__方法
  3. 自己类或基类的__new__方法
  4. 自己类或基类的__init__方法

 

所以先执行 FormMeta的init之后执行他的call方法

class FormMeta(type):

    def __init__(cls, name, bases, attrs):
type.__init__(cls, name, bases, attrs)
cls._unbound_fields = None
cls._wtforms_meta = None

 

接下来我们来继续分析FromMeta的call方法

 def __call__(cls, *args, **kwargs):

        if cls._unbound_fields is None:  # 第一次为None
fields = []
for name in dir(cls): # 获取类中的所有的静态方法和字段
if not name.startswith('_'): # 排除非私有方法和字段
unbound_field = getattr(cls, name) #反射获取字段名
if hasattr(unbound_field, '_formfield'): # Filed的静态标识
fields.append((name, unbound_field))
# We keep the name as the second element of the sort
# to ensure a stable sort.
fields.sort(key=lambda x: (x[1].creation_counter, x[0])) # 排序
cls._unbound_fields = fields # Create a subclass of the 'class Meta' using all the ancestors.
if cls._wtforms_meta is None: # 第一次为None
bases = []
for mro_class in cls.__mro__: # 或去派生类的Meta类
if 'Meta' in mro_class.__dict__:
bases.append(mro_class.Meta)
cls._wtforms_meta = type('Meta', tuple(bases), {})
return type.__call__(cls, *args, **kwargs)

 元类执行完成之后继续执行执行Form或BaseForm(自身或基类)的__new__和__init__方法

class BaseForm(object):

    def __init__(self, fields, prefix='', meta=DefaultMeta()):

        if prefix and prefix[-1] not in '-_;:/.':
prefix += '-'
# 初始化字段
self.meta = meta
self._prefix = prefix
self._errors = None
self._fields = OrderedDict() if hasattr(fields, 'items'):
fields = fields.items() translations = self._get_translations()
extra_fields = []
if meta.csrf:
self._csrf = meta.build_csrf(self)
extra_fields.extend(self._csrf.setup_form(self)) for name, unbound_field in itertools.chain(fields, extra_fields):
options = dict(name=name, prefix=prefix, translations=translations)
field = meta.bind_field(self, unbound_field, options)
self._fields[name] = field

  

  

  

flask WTForms源码分析及自定义WTForms的更多相关文章

  1. asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

    原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 在前面的文章中我们曾经涉及到ControllerActionInvoker类GetPara ...

  2. Flask之wtforms源码分析

    一.wtforms源码流程 1.实例化流程分析 # 源码流程 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._ ...

  3. JUnit源码分析 - 扩展 - 自定义Rule

    JUnit Rule简述 Rule是JUnit 4.7之后新加入的特性,有点类似于拦截器,可以在测试类或测试方法执行前后添加额外的处理,本质上是对@BeforeClass, @AfterClass, ...

  4. JUnit源码分析 - 扩展 - 自定义RunListener

    RunListener简述 JUnit4中的RunListener类用来监听测试执行的各个阶段,由RunNotifier通知测试去运行.RunListener与RunNotifier之间的协作应用的是 ...

  5. Netty源码分析之自定义编解码器

    在日常的网络开发当中,协议解析都是必须的工作内容,Netty中虽然内置了基于长度.分隔符的编解码器,但在大部分场景中我们使用的都是自定义协议,所以Netty提供了  MessageToByteEnco ...

  6. Django(63)drf权限源码分析与自定义权限

    前言 上一篇我们分析了认证的源码,一个请求认证通过以后,第二步就是查看权限了,drf默认是允许所有用户访问 权限源码分析 源码入口:APIView.py文件下的initial方法下的check_per ...

  7. Django(64)频率认证源码分析与自定义频率认证

    前言 有时候我们发送手机验证码,会发现1分钟只能发送1次,这是做了频率限制,限制的时间次数,都由开发者自己决定 频率认证源码分析 def check_throttles(self, request): ...

  8. ArrayList 源码分析和自定义ArrayList实现

    概述 ArrayList 是基于数组实现的,是一个能自动扩展的动态数组. ArrayList 是线程不安全的,多线程情况下添加元素会出现数组越界的情况,而且数组赋值操作不是原子操作,会导致多线程情况下 ...

  9. Django(60)Django内置User模型源码分析及自定义User

    前言 Django为我们提供了内置的User模型,不需要我们再额外定义用户模型,建立用户体系了.它的完整的路径是在django.contrib.auth.models.User. User模型源码分析 ...

随机推荐

  1. Order笔记-数据库创建

    过程: 1,为这个项目新建一个用户名(实例),专门用于这个项目 2,建表 问题: 列在此处不允许: 笔记: 建表设置默认值: alter table 表名 modify 字段名 default 默认值 ...

  2. canvas雪花

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. java两种动态代理方式的理解

    要理解动态代理,不妨先来看看一个静态代理的例子. 一.静态代理 以一个电商项目的例子来说明问题,比如我定义了一个订单的接口IOrder,其中有一个方法时delivery,代码如下. package c ...

  4. 翻译:MariaDB RENAME TABLE语句

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  5. [CSS]第一项和最后一项样式

    列表项的第一项距离顶部0.2rem,最后一项距离底部0.5rem .item:first-child { padding-top: .2rem; } .item:last-child { paddin ...

  6. org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

    异常信息 org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable represen ...

  7. Swift基础学习

    Swift基础学习  http://c.biancheng.net/cpp/html/2242.html 这个网站最近看了一下,对于基本语法解释概括的相对全面,如同重新练习一遍OC似的,挺全面的,谢谢 ...

  8. 快速自检电脑是否被黑客入侵过(Linux版)

    之前写了一篇快速自检电脑是否被黑客入侵过(Windows版), 这次就来写写Linux版本的. 前言 严谨地说, Linux只是一个内核, GNU Linux才算完整的操作系统, 但在本文里还是用通俗 ...

  9. arcgis api for js实现克里金插值渲染图--不依赖GP服务

    本篇的亮点是利用kriging.js结合arcgis api for js,实现克里金插值渲染图,截图如下: 具体实现的思路如下: 1.kriging.js开源js,可以实现针对容器canvas克里金 ...

  10. bzoj 4824: [Cqoi2017]老C的键盘

    Description 老 C 是个程序员.     作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 ...