首先我们来创建一个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. ASP.MVC当URL跳转时候参数的安全性

    一个页面跳转到另外一个页面直接将参数写在URL上面并不安全比如 http://XXXXXXXXXXX/meeting/shakeGroup?id=5381&uid=o0En_sj1J0bFgI ...

  2. 为什么说要搞定微服务架构,先搞定RPC框架?

    今天开始聊一些微服务的实践,第一块,RPC框架的原理及实践,为什么说要搞定微服务架构,先搞定RPC框架呢? 一.需求缘起 服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队 ...

  3. 询问Spring Bott和高并发框架两个问题

    这里我问两个问题,请大神告诉我. 第一个问题,如果我想用Spring Boot开发企业级的微服务,我该看哪些资料?比如数据库该如何配置?消息中间件该怎么设置?等等.或者可以推荐给我几本这方面的书. 第 ...

  4. nginx+zuul

      最近将公司的一些服务迁移到spring cloud了,感觉zuul智能路由的功能非常好用,比以前手动在nginx中添加localtion,upstream方便多了,但是服务域名的80端口被ngin ...

  5. Unix权限这点事

    Unix/Linux的权限管理还是比较复杂的,别人说看高级环境编程得看2,3遍.我想这应该是在Linux有了一定基础.但是我看的过程中确需要反复推敲,有些地方得翻来覆去看上5,6遍甚至更多,下面是自己 ...

  6. SVN 安装与使用教程总结

    转载:http://www.cnblogs.com/armyfai/p/3985660.html SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需 ...

  7. laravel基本信息

    1.Bundle是Laravel的扩展包组织形式或称呼.Laravel的扩展包仓库已经相当成熟了,可以很容易的帮你把扩展包(bundle)安装到你的应用中.你可以选择下载一个扩展包(bundle)然后 ...

  8. “乐”动人心--2017年10款最佳音乐类APP设计盘点

    在上下班的路上,听几首自己喜欢的音乐来打发无聊的等公交车和地铁的时间是现代年轻人的常态.音乐作为最能鼓动人心的"语言",也成为了人们在互联网生活里占比例最高的消费活动之一,一款好看 ...

  9. EL表达式隐式对象

    用户输入界面 ---------------------------------------------------------------------------------------- < ...

  10. lesson - 11 正则表达式

    正则就是有一定规律的字符串,有几个特殊符号很关键(. * + ? | ),我们平时不仅可以用命令行工具grep/sed/awk去引用正则,而且还可以把正则嵌入在nginx.apache.甚至php.p ...