flask WTForms源码分析及自定义WTForms
首先我们来创建一个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__方法,对于类的执行顺序
- 元类的__init__方法
- 元类的__call__方法
- 自己类或基类的__new__方法
- 自己类或基类的__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的更多相关文章
- asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证
原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 在前面的文章中我们曾经涉及到ControllerActionInvoker类GetPara ...
- Flask之wtforms源码分析
一.wtforms源码流程 1.实例化流程分析 # 源码流程 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._ ...
- JUnit源码分析 - 扩展 - 自定义Rule
JUnit Rule简述 Rule是JUnit 4.7之后新加入的特性,有点类似于拦截器,可以在测试类或测试方法执行前后添加额外的处理,本质上是对@BeforeClass, @AfterClass, ...
- JUnit源码分析 - 扩展 - 自定义RunListener
RunListener简述 JUnit4中的RunListener类用来监听测试执行的各个阶段,由RunNotifier通知测试去运行.RunListener与RunNotifier之间的协作应用的是 ...
- Netty源码分析之自定义编解码器
在日常的网络开发当中,协议解析都是必须的工作内容,Netty中虽然内置了基于长度.分隔符的编解码器,但在大部分场景中我们使用的都是自定义协议,所以Netty提供了 MessageToByteEnco ...
- Django(63)drf权限源码分析与自定义权限
前言 上一篇我们分析了认证的源码,一个请求认证通过以后,第二步就是查看权限了,drf默认是允许所有用户访问 权限源码分析 源码入口:APIView.py文件下的initial方法下的check_per ...
- Django(64)频率认证源码分析与自定义频率认证
前言 有时候我们发送手机验证码,会发现1分钟只能发送1次,这是做了频率限制,限制的时间次数,都由开发者自己决定 频率认证源码分析 def check_throttles(self, request): ...
- ArrayList 源码分析和自定义ArrayList实现
概述 ArrayList 是基于数组实现的,是一个能自动扩展的动态数组. ArrayList 是线程不安全的,多线程情况下添加元素会出现数组越界的情况,而且数组赋值操作不是原子操作,会导致多线程情况下 ...
- Django(60)Django内置User模型源码分析及自定义User
前言 Django为我们提供了内置的User模型,不需要我们再额外定义用户模型,建立用户体系了.它的完整的路径是在django.contrib.auth.models.User. User模型源码分析 ...
随机推荐
- 详解Office Add-in 清单文件
作者:陈希章 发表于2017年12月8日 前言 我们都知道,一个Office Add-in,最主要是由两个部分组成的:清单文件(manifest)和真正要用来执行的网站. 清单文件其实是一个标准的XM ...
- 【转载】Java系列笔记(3) - Java 内存区域和GC机制
Java系列笔记(3) - Java 内存区域和GC机制 转载:原文地址http://www.cnblogs.com/zhguang/p/3257367.html 目录 Java垃圾回收概况 Java ...
- idea java 1.5 过时
解决方案: 1.修改maven的setting.xml文件,添加以下内容,此设置为jdk1.8 <profile> <id>jdk-1.8</id> <act ...
- 60、jQuery其余操作
上篇主要介绍了jQuery,和一些基本用法,这篇主要讲解动画.常用事件.还有一些jQuery的补充内容. 本篇导航: 动画 常用事件 插件 jQuery API 中文文档 一.动画 1.基本 show ...
- 【java】java.lang.Math:public static long round(double a)和public static int round(float a)
package math; public class TestMath_round { public static void main(String[] args) { System.out.prin ...
- Django的设计模式
MVC模式 MVC将应用程序分解为三个组成部分:mode(模型).view(视图).control(控制器),其中: M 管理应用程序的状态(通常存储到数据库中),并榆树改变状态的行为(或者叫&quo ...
- Java之数据类型,变量赋值
Java中的基础数据类型(四类八种): 1.整数型 byte----使用byte关键字来定义byte型变量,可以一次定义多个变量并对其进行赋值,也可以不进行赋值.byte型是整型中所分配的内存空间是最 ...
- Linux 文件API
9/19/2017 开始攻读<LinuxC编程实战>,这是相关的笔记 1.创建 int creat(const char *filename, mode_t mode); 参数mode指 ...
- cell的复用机制
以下全部都是转载自别人的博客:http://blog.sina.com.cn/s/blog_9c3c519b01016aqu.html 转自:http://www.2cto.com/kf/201207 ...
- Java之线程安全中的三种同步方式
一个程序在运行起来时,会转换为进程,通常含有多个线程. 通常情况下,一个进程中的比较耗时的操作(如长循环.文件上传下载.网络资源获取等),往往会采用多线程来解决. 比如,现实生活中,银行取钱问题.火车 ...