(三十)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.rhkb.cn/news/356321.html

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

相关文章

如何用 Google Chrome 浏览器浏览经过 XSLT 渲染的 XML 文件

对于经过XSLT渲染的XML文件,本来,可以直接用 IE (Internet Explorer) 打开,就能看到渲染之后的样子,很方便。但是后来,微软把 IE 换成了 Microsoft Edge,按理说这是比 IE 更先进的浏览器,可是偏…

Stable Diffusion vs DALL·E3

大模型技术论文不断,每个月总会新增上千篇。本专栏精选论文重点解读,主题还是围绕着行业实践和工程量产。若在某个环节出现卡点,可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技(Mamba,xLSTM,KAN)则提…

CSS详解

盒子模型&#xff08;box-sizing&#xff09; line-height与height CSS选择符和可继承属性 属性选择符&#xff1a; 示例&#xff1a;a[target"_blank"] { text-decoration: none; }&#xff08;选择所有target"_blank"的<a>元素&#xff09; /* 选…

NeRF从入门到放弃3: EmerNeRF

https://github.com/NVlabs/EmerNeRF 该方法是Nvidia提出的&#xff0c;其亮点是不需要额外的2D、3Dbox先验&#xff0c;可以自动解耦动静field。 核心思想&#xff1a; 1. 动、静filed都用hash grid编码&#xff0c;动态filed比静态多了时间t&#xff0c;静态的hash编码输入是…

项目启动 | 盘古信息助力鼎阳科技开启智能制造升级新征程

在全球数字化浪潮不断涌动的背景下&#xff0c;电子信息行业正迎来转型升级的关键阶段。近日&#xff0c;盘古信息与深圳市鼎阳科技股份有限公司&#xff08;简称“鼎阳科技”&#xff0c;股票代码&#xff1a;688112&#xff09;正式启动了IMS数字化智能制造工厂项目&#xff…

windows环境下,怎么查看本机的IP、MAC地址和端口占用情况

1.输入ipconfig,按回车。即查看了IP地址&#xff0c;子码掩码&#xff0c;网关信息。 2.输入ipconfig/all,按回车。即查看了包含IP地址&#xff0c;子码掩码&#xff0c;网关信息以及MAC地址 3.我们有时在启动应用程序的时候提示端口被占用&#xff0c;如何知道谁占有了我们需要…

C#实现卷积平滑(图像处理)

在C#中使用卷积滤波器来实现图像平滑处理&#xff0c;我们可以使用 System.Drawing 库来操作图像。下面是一个具体的示例&#xff0c;演示如何加载图像、应用卷积平滑滤波器&#xff0c;并保存处理后的图像。 1. 安装 System.Drawing.Common 首先&#xff0c;确保你已经安装了…

【Leetcode】2663. 字典序最小的美丽字符串

题目 题目链接&#x1f517;如果一个字符串满足以下条件&#xff0c;则称其为 美丽字符串 &#xff1a; 它由英语小写字母表的前 k 个字母组成。它不包含任何长度为 2 或更长的回文子字符串。 给你一个长度为 n 的美丽字符串 s 和一个正整数 k 。请你找出并返回一个长度为 n…

Python | Leetcode Python题解之第166题分数到小数

题目&#xff1a; 题解&#xff1a; class Solution:def fractionToDecimal(self, numerator: int, denominator: int) -> str:if numerator % denominator 0:return str(numerator // denominator)s []if (numerator < 0) ! (denominator < 0):s.append(-)# 整数部…

软件缺陷及JIRA工具

一、软件缺陷及跟踪流程 1&#xff0c;软件缺陷信息 案例 &#xff08;1&#xff09;缺陷报告的基本内容 缺陷的标题 预置条件 重现步骤 期望结果 实际结果 &#xff08;2&#xff09;软件缺陷的状态 新建 打开 修复 关闭 &#xff08;3&#xff09;软件缺陷的严重程度 …

JAVA医院绩效考核系统源码 功能特点:大型医院绩效考核系统源码

JAVA医院绩效考核系统源码 功能特点&#xff1a;大型医院绩效考核系统源码 医院绩效管理系统主要用于对科室和岗位的工作量、工作质量、服务质量进行全面考核&#xff0c;并对科室绩效工资和岗位绩效工资进行核算的系统。医院绩效管理系统开发主要用到的管理工具有RBRVS、DRGS…

云徙科技助力竹叶青实现用户精细化运营,拉动全渠道销售额增长

竹叶青茶以其别具一格的风味与深厚的历史底蕴&#xff0c;一直被誉为茶中瑰宝。历经千年的传承与创新&#xff0c;竹叶青不仅坚守着茶叶品质的极致追求&#xff0c;更在数字化的浪潮中&#xff0c;率先打破传统&#xff0c;以科技力量赋能品牌&#xff0c;成为茶行业的领军者。…

Python抓取高考网图片

Python抓取高考网图片 一、项目介绍二、完整代码一、项目介绍 本次采集的目标是高考网(http://www.gaokao.com/gkpic/)的图片,实现图片自动下载。高考网主页如下图: 爬取的流程包括寻找数据接口,发送请求,解析图片链接,向图片链接发送请求获取数据,最后保存数据。 二…

示例:WPF中在没有MouseDoubleClick的控件中如何识别双击

一、目的&#xff1a;由于MouseDoubleClick控件是在Control中实现&#xff0c;那么在底层控件如Grid中想要类似功能如何实现&#xff0c;这里通过MouseDown的事MouseButtonEventArgs参数去实现 二、实现 定义Grid并注册Grid的MouseDown事件 <Grid Background"Transpa…

GIT回滚

1. 使用 git revert git revert 命令会创建一个新的提交&#xff0c;这个提交会撤销指定提交的更改。这通常用于公共分支&#xff08;如 main 或 master&#xff09;&#xff0c;因为它不会重写历史。 git revert HEAD # 撤销最近的提交 # 或者指定一个特定的提交哈希值 …

MFC GDI绘制卡通人物

文章目录 主要代码完整visual studio工程下载主要代码 // DrawFrogView.cpp : implementation of the CDrawFrogView class //#include "stdafx.h" #include "DrawFrog.h"#include "DrawFrogDoc.h" #include "DrawFrogView.h"#includ…

MySQL的DML语句

文章目录 ☃️概述☃️DML☃️添加数据☃️更新和删除数据☃️DML的重要性 ☃️概述 MySQL 通用语法分类 ● DDL: 数据定义语言&#xff0c;用来 定义数据库对象&#xff08;数据库、表、字段&#xff09; ● DML: 数据操作语言&#xff0c;用来对数据库表中的数据进行增删改 …

【源码】人力资源管理系统hrm功能剖析及源码

eHR人力资源管理系统&#xff1a;功能强大的人力资源管理工具 随着企业规模的不断扩大和业务需求的多样化&#xff0c;传统的人力资源管理模式已无法满足现代企业的需求。eHR人力资源管理系统作为一种先进的管理工具&#xff0c;能够为企业提供高效、准确、实时的人力资源管理。…

鞋子分类数据集17399张69类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;17399 分类类别数&#xff1a;69 类别名称:[“0”,“1”,“2”,“3”,“4”…

使用asyncua模块的subscribe_data_change监控opcua的Server节点数据变化

报错信息如下&#xff1b; ERROR:asyncua.common.subscription:DataChange subscription created but handler has no datachange_notification method 上述报错原因在于创建监控句柄SubscriptionHandler类时&#xff0c;节点数据变化的函数名称有问题&#xff0c;不是默认的da…