(三十)Flask之wtforms库【剖析源码上篇】

每篇前言:

  • 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者

  • 🔥🔥本文已收录于Flask框架从入门到实战专栏:《Flask框架从入门到实战》
  • 🔥🔥热门专栏推荐:《Python全栈系列教程》、《爬虫从入门到精通系列教程》、《爬虫进阶+实战系列教程》、《Scrapy框架从入门到实战》、《Flask框架从入门到实战》、《Django框架从入门到实战》、《Tornado框架从入门到实战》、《前端系列教程》。
  • 📝​📝本专栏面向广大程序猿,为的是大家都做到Python全栈技术从入门到精通,穿插有很多实战优化点。
  • 🎉🎉订阅专栏后可私聊进一千多人Python全栈交流群(手把手教学,问题解答); 进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
  • 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!

在这里插入图片描述

如果在项目中需要使用wtforms,那么脑海中应该有个清晰的用wtforms库写类的架子:

# 半伪代码:
class LoginForm(Form):name = StringField(正则=[验证规则1, 验证规则2, ], 插件=Input框)password = StringField(正则=[验证规则1, 验证规则2, ], 插件=Password框)

wtforms实现原理主要从三个方面进行剖析:form类创建过程、实例化过程、验证过程。从整体看其实现原理就是将每个类别的功能(如Filed、validate、meta等)通过form进行组织、封装,在form类中调用每个类别对象的方法实现数据的验证和html的渲染。这里先总结下验证流程:

  1. for循环每个字段;
  2. 执行该字段的pre_validate钩子函数;
  3. 执行该字段参数的validators中的验证方法和validate_字段名钩子函数(如果有);
  4. 执行该字段的post_validate钩子函数;
  5. 完成当前字段的验证,循环下一个字段,接着走该字段的2、3、4流程,直到所有字段验证完成;

以(二十八)篇文章中的【用户登录验证】这部分的代码为例一点点进行剖析~

作者写上一篇文章很大一个目的是,让大家在分析代码时,一看定义类的部分,就要条件反射般的想到元类这一玩意!

当前类有没有指定自定义元类,如果没有指定自定义元类,那么当前类继承的父类呢?继承的父类的父类呢???

【如果有的话,在代码执行到下图箭头所指时,就会触发对应自定义元类的init魔法方法!】

在这里插入图片描述

所以当代码执行到上图箭头所指位置时,究竟执行了什么逻辑,就要往这个类的父类追踪看一看:
在这里插入图片描述

"""
上图箭头所指那句等价于:
class NewBase(BaseForm, metaclass=FormMeta):passclass Form(NewBase):pass
"""

在这里插入图片描述

这就找到了!父类Form的父类NewBase自定义了元类FormMeta,所以就会执行这个元类的init魔法方法:
在这里插入图片描述

上图所示代码中,type.__init__(cls, name, bases, attrs) 是在调用基类 type__init__ 方法。

这样的调用是为了确保基类的 __init__ 方法被适当地调用,以便正确地初始化类对象。

上图cls就是当前类—LoginForm类~

所以代码执行到最开始那句时:

【类里已经有了两个字段,而且值为None】

在这里插入图片描述

代码继续往下执行:
在这里插入图片描述

当上图部分代码都执行完后,LoginForm类的user和pwd的值会是下图这俩吗?

请注意这俩都对应实例化了一个类,所以要具体分析一下:

在这里插入图片描述

先来看user,它继承的类有没有指定自定义元类:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

会发现到顶了也没有指定的,所以继续会执行类的new魔法方法,一个个类往上找:

在这里插入图片描述

这个if不成立,所以走else。返回了一个使用 UnboundField 类创建的对象实例,参数有cls,就是当前类StringField,并携带着StringField的所有参数。

怎么理解这个操作呢?

因为StringField功能有限,这里想要多加一个功能,就通过给StringField外面再套一层,这就是UnboundField,它实现了计数器的功能(下面会讲这是个啥)!

所以LoginForm类里的name和pwd的值应该是:

在这里插入图片描述

继续来看看UnboundField类:

在这里插入图片描述

所以当LoginForm类的代码执行完,LoginForm类就已经有了注释部分那些值:

在这里插入图片描述

代码继续执行:

当代码执行到下图红色箭头所示时,这是LoginForm类的实例化,代码内部执行流程就如下图红框所示:

在这里插入图片描述

一步步来,先来看FormMeta的call魔法方法:

在这里插入图片描述

当代码执行到上图红色箭头所示位置时,LoginForm类的_unbound_fields属性就有值了:

在这里插入图片描述

继续看call方法:
在这里插入图片描述

LoginForm类里面是没有Meta的,继续看Form类,发现有:

在这里插入图片描述
在这里插入图片描述

当代码执行到上图红色箭头所示位置时,LoginForm类的_wtforms_meta属性也有值了:

在这里插入图片描述

call方法结束,接下来来看LoginForm的new魔法方法,会发现没有;

所以继续来看LoginForm的init魔法方法:

在这里插入图片描述

先看上图红框所示部分代码,重点是 —> 最后一句调用父类的初始化方法,所以看父类BaseForm的init魔法方法中对传入的参数做了什么操作:

注意参数self._unbound_fields就是前面说的:
在这里插入图片描述

class BaseForm(object):"""Base Form Class.  Provides core behaviour like field construction,validation, and data and error proxying."""def __init__(self, fields, prefix='', meta=DefaultMeta()):""":param fields:A dict or sequence of 2-tuples of partially-constructed fields.:param prefix:If provided, all fields will have their name prefixed with thevalue.:param meta:A meta instance which is used for configuration and customizationof WTForms behaviors."""if prefix and prefix[-1] not in '-_;:/.':prefix += '-'self.meta = metaself._prefix = prefixself._errors = Noneself._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))"""fields:[('name', UnboundField(simple.StringField, *args, **kwargs, creation_counter=1)),('pwd', UnboundField(simple.PasswordField, *args, **kwargs, creation_counter=2)),]extra_fields(下面我会讲一下这个是干啥的)我是没有传的,所以下面循环就是循环fields这个列表~"""for name, unbound_field in itertools.chain(fields, extra_fields):options = dict(name=name, prefix=prefix, translations=translations)"""name: 'name';   unbound_field = UnboundField(simple.StringField, *args, **kwargs, creation_counter=1)下面这句就是把simple.StringField拿出来实例化:field = simple.StringField()"""field = meta.bind_field(self, unbound_field, options)self._fields[name] = field"""上述for循环执行完后:self._fields = {'name': simple.StringField(),'pwd': simple.PasswordField()}"""

所以,当代码执行到此,LoginForm对象(因为执行init就完成了类的实例化操作)里就有了值(注意:上面都是往LoginForm类里加的数据):
在这里插入图片描述

所以,回到Form类的init魔法方法,继续往下看:

在这里插入图片描述

当上图红框部分代码执行完毕后,LoginForm对象里就又通过setattr设置了两个实例属性(将所有的field拆出来给到了LoginForm对象):

在这里插入图片描述

这样我们才能执行的form.name或者form.pwd这些。

还差最后一句,init就也执行完了,那么最后一局self.process()是干了啥呢?

它就是给每个input加默认值以及做验证操作的。

如下就是讲了下如何给input框加默认值?以及如何生成的input框?

在这里插入图片描述

页面上也是form.user这样就生成了对应的input框:

在这里插入图片描述

如果想给这个input一个默认值呢?

在这里插入图片描述

接下来就看看为何执行simple.StringField().__str__就生成了input框:
在这里插入图片描述

没有str魔法方法,继续看父类Field:
在这里插入图片描述

这样就会触发当前类的call魔法方法:

在这里插入图片描述

进去:

在这里插入图片描述

field.widget()就是StringField对象里的widget(插件)加括号,就会触发插件对象的call魔法方法,所以继续进:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

所以总结这个流程,生成input框的任务是交给了TextInput插件去做的:

在这里插入图片描述

  • 小问题:form是否支持for循环?

    【Tips:一个对象支持for循环,那么这个类内部肯定实现了iter魔法方法~】

    for item in form:print(item) 
    

在这里插入图片描述

        self._fields = {'name': simple.StringField(),'pwd': simple.PasswordField()}

然后print就会执行每个字段的str魔法方法,所以就会打印user和pwd的input框前端代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/27313.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

45.Python-web框架-Django - 开始建立第一个项目

目录 1.django是什么? 2.Pycharm 社区版,还是专业版? 3.开始django,Pycharm专业版 创建一个Django项目 运行一个Django项目 运行方法一,命令行的方式 运行方法二,配置Django Server的方式 4.django尊…

gpio-0设置成输出失败的原因

原因 spi驱动先设置gpio-0成了输出; 但是后面其他驱动,使用of_property_read_u32获取设备树节点的属性时,没去判断返回值;而直接使用参数返回的0,导致gpio-0又被设置成了输入 实例 正常的如下,gpio显示…

入职3年-我如何做一名AI产品经理(文末福利)

引言 从2021年校招加入京东开始,我一直从事AI产品经理的工作,有幸见证了AI行业的热情从一台台服务器烧到了全世界各个角落,也见证了京东AI中台团队的影响力如何一步步的扩大。从21年的迷茫到24年的坚定,很庆幸我正走在适合自己的…

【C++】类的默认成员函数

类的默认成员函数 类的六个默认成员函数构造函数构造函数的概念构造函数的特性 析构函数析构函数的概念析构函数的特性 构造函数与析构函数的调用顺序拷贝构造拷贝构造的概念拷贝构造的特性赋值运算符重载运算符重载赋值运算符重载前置与后置重载输入输出流重载 const修饰成员实…

高精度减法

高精度减法 两个高精度整数的减法题目思路实现代码实现 两个任意符号的高精度加减法 两个高精度整数的减法 高精度指的是数字的大小非常非常大,最多能有10的5次方 的 位数。 本次计算的两个数均为 正数,如何求负数会在最后提到。 题目 给定两个正整数…

解决浏览器缩放的时候,重新设置滚动条的位置,使页面滚动条固定悬浮在页面底部

项目场景: 浏览器调试页面兼容页面时,缩放页面宽度,整体超出时滚动条出现在页面最底部,不是悬浮在页面下面,只有滚动到最底部才出现,需要的是悬浮在页面底部,不是滚动到最下面才出现 解决方案…

java面试整合全套

什么是Java (定义 优点) java是一个平台,由jvm和Java应用编程接口构成的一门面向编程语言。 不仅吸收了C语言的各种优点,还摒弃了c语言里面的多继承,指针等概念,因此java的特征主要有功能强大和简单易用的特征。 jav…

uniapp chooseVideo和uploadFile 选择视频或照片上传抖快平台踩坑

先贴代码 uni.chooseVideo({sourceType: [album],fail:(err)>{console.log(TAG, "chooseVideo-failerr:", err)page.resetUploadFileField()if (err.errNo 10200 || chooseVideo:fail take video fail err.errMsg || chooseVideo:fail auth deny err.errMsg) …

排序-插入排序

基本介绍 插入排序属于内部排序算法,是对于排序的元素以插入的方式找寻该元素的适当位置,以达到排序的日的。 插入排序(Insertion Sorting)的基本思想 把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素&#xff…

架构设计-如何安全地传输密码

java web 项目中经常会遇到登录或注册的场景,如果查看浏览器的 network 网络请求时,用户的密码以明文方式传输,会造成很多安全隐患,这就涉及到密码如何安全传输的问题。 数据加密的重要性不言而喻,通用的加密技术有 哈希散列、对称加密、非对称加密。 哈希散列 哈希散列是…

论徐州高防IP的作用有哪些?

高防IP是一个专门解决大流量攻击的安全防护产品,能够支持网站和非网站类业务的DDOS防护和CC防护,是保护企业网络安全的重要手段,大部分的企业网站会选择应用高防IP,来保障企业业务的稳定可用性。 接下来小万就来介绍一下高防IP的作…

如何有效限制IP多次重新访问网站

哈喽,大家好呀,淼淼又来和大家见面啦,在如今的网络世界中,有时候我们需要限制某些IP地址多次重新访问网站,以保护网站的安全性和用户体验。这一期淼淼将介绍一些常见的方法,帮助你有效地限制IP多次重新访问…

FPGA Verilog模块化设计入门篇一

随着电子技术的快速发展,现场可编程门阵列(FPGA)已成为现代电子系统设计中不可或缺的一部分。FPGA的灵活性、可重构性和高性能使得它成为处理复杂算法、加速数据处理和实现特定功能的理想选择。然而,随着系统复杂性的增加&#xf…

【npm】一款时间日期工具库,你可以使用它来实现精美日历或欢迎页

时间转换工具 author: Vincamailbox: 237690966qq.comUpdateTime: 2024/6/13 15:29:18 安装 npm install v_datejs引用 import v from "v_datejs";使用 html&#xff1a; <template><code>{{ v.tm() }}</code> </template>js&#xff…

go-zero整合Excelize并实现Excel导入导出

go-zero整合Excelize并实现Excel导入导出 本教程基于go-zero微服务入门教程&#xff0c;项目工程结构同上一个教程。 本教程主要实现go-zero框架整合Excelize&#xff0c;并暴露接口实现Excel模板下载、Excel导入、Excel导出。 go-zero微服务入门教程&#xff1a;https://blo…

Mysql学习(九)——存储引擎

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 七、存储引擎7.1 MySQL体系结构7.2 存储引擎简介7.3 存储引擎特点7.4 存储引擎选择7.5 总结 七、存储引擎 7.1 MySQL体系结构 连接层&#xff1a;最上层是一些客户…

Web前端大结局:揭秘四重境界、五大法则、六大技巧与七大未来趋势

Web前端大结局&#xff1a;揭秘四重境界、五大法则、六大技巧与七大未来趋势 在浩瀚无垠的互联网世界中&#xff0c;Web前端技术以其独特的魅力&#xff0c;吸引着无数开发者投身其中。今天&#xff0c;我们将一起揭开Web前端的大结局&#xff0c;深入探讨其四重境界、五大法则…

自然语言处理领域的重大挑战:解码器 Transformer 的局限性

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

MFC四种方法编写多线程

本文以四个demo为例&#xff0c;对MFC的多线程进行学习。学习的过程中写了四个demo&#xff0c;将其做成笔记&#xff0c;发布在csdn上面。 mfc多线程demo1 volatile BOOL m_bRun; CEdit* edit; void ThreadFunc(){CTime time;CString strTime;m_bRun true;while(m_bRun){ti…

聚焦赛宁网安竞赛平台+赛事服务,引领网络安全竞赛新潮流

第八届XCTF总决赛将在2024年6月22日于中国成都震撼开启&#xff0c;本届总决赛分为个人Live Solo和团队KOH巅峰对决两个赛道&#xff0c;从个人和团队多角度全方位考察参赛人员的竞技水平。 巅峰对决 智慧的火花在此碰撞 个人Live Solo赛制 Live Solo赛分为晋级赛和Solo赛。…