(三十)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…

FPGA Verilog模块化设计入门篇一

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

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

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

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

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

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

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

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

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

贝壳APP渗透测试WP

前期配置 环境说明 使用PIXEL 4手机,为Android 12系统 APP名为贝壳找房,包名com.lianjia.beike,版本号3.01.10,截至2024/05/07为最新版,小米应用市场下载 绕过反Frida机制 可以参考往期推送,《绕过最新…

2分钟用手机开发一个ChatBot

前言: 在上一期,我们测评了CodeFlying,用它开发出了一个复杂推文管理系统,然后体验了一下它的热门应用:AI智能机器人。今天咱就继续用CodeFlying来开发一个属于我们自己的聊天机器人。 老规矩,我们先在手机…

【qt】平面CAD(计算机辅助设计 )项目 上

CAD 一.前言二.界面设计三.提升类四.接受槽函数五.实现图形action1.矩形2.椭圆3.圆形4.三角形5.梯形6.直线7.文本 六.总结 一.前言 用我们上节课刚刚学过的GraphicsView架构来绘制一个可以交互的CAD项目! 效果图: 二.界面设计 添加2个工具栏 需要蔬菜的dd我! 添加action: …

遗传算法求解车间调度问题(附python代码)

背景介绍 车间调度问题(Job Shop Scheduling Problem, JSSP)是一类经典的组合优化问题,它在制造业和生产管理中有着广泛的应用。JSSP 的目标是对车间中的一系列作业进行排程,以使得作业在不同机器上的加工顺序是最优的&#xff0…

万相台的功能是什么?如何使用万相台?

1.特点: 万相台是一个智能渠道,可控性弱,高转化,人群&关键词是黑盒; 2.场景多: 有拉新快、活动加速、上新快、货品加速、活动加速、多目标直投、全站推等; 3.扣费逻辑:cpc付…

Sm4【国密4加密解密】

当我们开发金融、国企、政府信息系统时,不仅要符合网络安全的等保二级、等保三级,还要求符合国密的安全要求,等保测评已经实行很久了,而国密测评近两年才刚开始。那什么是密码/国密?什么是密评?本文就关于密…

Linux:线程概念 线程控制

Linux:线程概念 & 线程控制 线程概念轻量级进程 LWP页表 线程控制POSIX 线程库 - ptherad线程创建pthread_createpthread_self 线程退出pthread_exitpthread_cancelpthread_joinpthread_detach 线程架构线程与地址空间线程与pthread动态库 线程的优缺点 线程概念…

机器学习与数据挖掘知识点总结(二)分类算法

目录 1、什么是数据挖掘 2、为什么要有数据挖掘 3、数据挖掘用在分类任务中的算法 朴素贝叶斯算法 svm支持向量机算法 PCA主成分分析算法 k-means算法 决策树 1、什么是数据挖掘 数据挖掘是从大量数据中发现隐藏在其中的模式、关系和规律的过程。它利用统计学、机器学…