首先我们来创建一个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. redis的事务(简单介绍)

    1.简单描述 redis对事务的支持目前还是比较简单.redis只能保证一个client发起的事务中的命令是可以连续的执行,而中间不会插入其他client的命令.由于redis是但现场来处理所有cli ...

  2. 使用Intellij IDEA的svn时提示出错:Can't use Subversion command line client: svn

    问题 原因是安装SVN的时候没有安装command-line功能,要单独安装VisualSVN 下载页面:http://subversion.apache.org/packages.html SVN1 ...

  3. 为什么epoll会那么高效

    参考(原文简直超赞):https://zhidao.baidu.com/question/687563051895364284.html下面是我结合原文写的,为了便于自己理解:关于阻塞和非阻塞的理解可 ...

  4. Noip2016换教室(期望+DP)

    Description 题目链接:Luogu Solution 这题结合了DP和概率与期望,其实只要稍微知道什么是期望就可以了, 状态的构造很关键,\(F[i][j][0/1]\)表示已经到第\(i\ ...

  5. [数据结构]C语言二叉树的实现

    树和图是数据结构中比较麻烦的东西,里面涉及的概念比较多,也最有用, 就比如一般树广泛应用于人工智能的博弈上,而基于图的广度优先和深度优先搜索也广泛应用于人工智能寻路上面 首先我们要把树进行分类: &g ...

  6. Microsoft Visual Studio 2012旗舰版(VS2012中文版下载)官方中文版

    Microsoft Visual Studio 2012 Ultimate旗舰版(VS2012中文版下载)是一个最先进的开发解决方案,它使各种规模的团队能够设计和创建出使用户欣喜的引人注目的应用程序. ...

  7. SQL企业级面试题

    链接:90root MySQL企业面试题 1. 开发有一堆数据插入,如何防止插入的中文数据产生乱码? 2. 如何批量更改数据库表的引擎,如:myisam改为innodb 3. 如何批量更改数据库字符集 ...

  8. lesson - 6 Linux下磁盘管理

    1. 查看磁盘或者目录的容量df  查看磁盘各分区使用情况   不加参数以k为单位   df -i inode数,df -h  以G或者T或者M   df -m  以M单位显示  du 查看目录或者文 ...

  9. (一)DOM 常用操作 —— “查找”节点

    在 DOM 树中,如果想要操作一个节点,那么首先要"查找"到这个节点.查找节点的方法由 Document 接口定义,而该接口由 JavaScript 中的 document 对象实 ...

  10. vuejs实现本地数据的筛选分页

    今天项目需要一份根据本地数据的筛选分页功能,好吧,本来以为很简单,网上搜了搜全是ajax获取的数据,这不符合要求啊,修改起来太费力气,还不如我自己去写,不多说直接上代码 效果图: 项目需要:点击左侧进 ...