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模型源码分析 ...
随机推荐
- cs231n --- 3 : Convolutional Neural Networks (CNNs / ConvNets)
CNN介绍 与之前的神经网络不同之处在于,CNN明确指定了输入就是图像,这允许我们将某些特征编码到CNN的结构中去,不仅易于实现,还能极大减少网络的参数. 一. 结构概述 与一般的神经网络不同,卷积神 ...
- JSR系列开篇
JSR是Java Specification Requests的缩写,意思是Java 规范提案.是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求.任何人 ...
- 《程序员的职业素养》【PDF】下载
<程序员的职业素养>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382243 内容介绍 <程序员的职业素养>是编程大 ...
- node作为客户端请求第三方
var http = require('http'); let util = require('util'); http.get('http://www.imooc.com/u/card',funct ...
- Base64转换二进制文件对象 Blob/Base64转换 File 对象
function convertBase64UrlToBlob(urlData) { var arr = dataurl.split(','),//去掉url的头,并转换为byte type = ar ...
- iOS App稳定性指标及监测
一个App的稳定性,主要决定于整体的系统架构设计,同时也不可忽略编程的细节,正所谓"千里之堤,溃于蚁穴",一旦考虑不周,看似无关紧要的代码片段可能会带来整体软件系统的崩溃.尤其因为 ...
- Visual Studio 2017 : client version 1.22 is too old
使用Vs2017 编译 eShopOnContainers-ServicesAndWebApps 时,报了错误: Microsoft.DotNet.Docker.CommandLineClientEx ...
- Windows as a Service(4)——使用Intune管理Windows10更新
这是这个系列的最后一篇文章,我已经花了三篇的篇幅和大家分享有关于Windows as a Serivce的相关内容,链接如下: Windows as a Service(1)-- Windows 10 ...
- 3.sass的数据类型与函数
数据类型 在sass里有数字.字符串.列表.颜色等类型 在cmd里 输入 sass -i 就会进入到交互模式,输入的计算可以马上得到结果 type-of()可以用来得到数据类型,如: type-of( ...
- IDE 、SATA、SCSI 的区别
http://chuanwang66.iteye.com/blog/1134784 IDE IDE的英文全称为“Integrated Drive Electronics”,即“电子集成驱动器”,它的 ...