每篇前言:
- 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者
- 🔥🔥本文已收录于Flask框架从入门到实战专栏:《Flask框架从入门到实战》
- 🔥🔥热门专栏推荐:《Python全栈系列教程》、《爬虫从入门到精通系列教程》、《爬虫进阶+实战系列教程》、《Scrapy框架从入门到实战》、《Flask框架从入门到实战》、《Django框架从入门到实战》、《Tornado框架从入门到实战》、《前端系列教程》。
- 📝📝本专栏面向广大程序猿,为的是大家都做到Python全栈技术从入门到精通,穿插有很多实战优化点。
- 🎉🎉订阅专栏后****可私聊进一千多人Python全栈交流群(手把手教学,问题解答);进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
- 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!
关于上篇文章剖析源码的整体流程——画个简单的示意图,大家对着在脑中回忆下:
第一阶段:创建类LoginForm
第二阶段:form = LoginForm()
第三阶段:print(form.pwd)
(StringField和TextInput不止这俩,有多个)
验证流程分析:
此处formdata就携带了前端用户输入的数据。
formdata参数有三种类型,具体取决于传过来的参数以什么方式取值:
form = LoginForm(formdata=request.form)# 值.get('k1')、值.getlist()
form = LoginForm(data={'k1':'v1'})# 值['k1']
form = LoginForm(obj=对象)# 值.k1
继续,看form.validate() ——> 分析验证流程:
LoginForm没有validate方法,看父类:
defvalidate(self):"""
Validates the form by calling `validate` on each field, passing any
extra `Form.validate_<fieldname>` validators to the field validator.
"""
extra ={}for name in self._fields:# 循环每个field #寻找当前类中以 validate_字段名 匹配的方法,例如pwd字段就寻找validate_pwd,也就是钩子函数
inline =getattr(self.__class__,'validate_%s'% name,None)if inline isnotNone:
extra[name]=[inline]# 把钩子函数放到extra字典中returnsuper(Form, self).validate(extra)# 接着调用父类的validate方法
先获取所有每个字段定义的 validate_+字段名 匹配的方法,并保存在extra字典中,再执行父类的validate方法:
defvalidate(self, extra_validators=None):
self._errors =None
success =Truefor name, field in iteritems(self._fields):# 循环字段的名称和对象,比如第一个就分别是user和StringField对象if extra_validators isnotNoneand name in extra_validators:# 判断该字段是否有钩子函数
extra = extra_validators[name]# 获取到钩子函数else:
extra =tuple()ifnot field.validate(self, extra):# 执行当前字段对象的validate方法
success =Falsereturn success
该方法主要用于和需要验证的字段进行匹配(并且携带上每个字段的钩子函数),执行每个字段对象的validate方法:
defvalidate(self, form, extra_validators=tuple()):
self.errors =list(self.process_errors)
stop_validation =False# Call pre_validatetry:
self.pre_validate(form)# 先执行字段中的pre_validate方法,这是一个自定义钩子函数except StopValidation as e:if e.args and e.args[0]:
self.errors.append(e.args[0])
stop_validation =Trueexcept ValueError as e:
self.errors.append(e.args[0])# Run validatorsifnot stop_validation:
chain = itertools.chain(self.validators, extra_validators)# 链接字段中的validators和validate_+字段名 验证
stop_validation = self._run_validation_chain(form, chain)# 执行每一个验证规则,self.validators先执行# Call post_validatetry:
self.post_validate(form, stop_validation)except ValueError as e:
self.errors.append(e.args[0])returnlen(self.errors)==0
在该方法中,先会执行内部预留给用户自定义的字段的pre_validate方法,
再将字段中的验证规则(validators也就是我们定义的validators=[validators.DataRequired()],)和钩子函数(validate_+‘字段名’)拼接在一起执行,
注意这里的validators先执行而字段的钩子函数后执行,继续来看怎么执行的:
def_run_validation_chain(self, form, validators):for validator in validators:# 循环每个验证规则try:
validator(form, self)# 传入用户提交的数据并执行,如果是对象执行__call__,如果是函数直接调用except StopValidation as e:if e.args and e.args[0]:
self.errors.append(e.args[0])# 如果有错误,追加到整体错误中returnTrueexcept ValueError as e:
self.errors.append(e.args[0])returnFalse
很明显就是循环每一个验证规则,并执行,有错误追加到整体错误中,接着我们回到validate方法中,接着又会执行post_validate,这也是内置钩子函数,允许用户自己定义,最后这个字段的数据验证完成了,而在开始的for循环,循环结束意味着整个验证过程结束。
defpost_validate(self, form, validation_stopped):"""
Override if you need to run any field-level validation tasks after
normal validation. This shouldn't be needed in most cases.
:param form: The form the field belongs to.
:param validation_stopped:
`True` if any validator raised StopValidation.
"""pass
总结:
每个字段进行验证的时候:
- 字段的
pre_validate
【钩子函数——预留的扩展】 - 字段的
_run_validation_chain
,对正则和字段的钩子函数进行校验 - 字段的
post_validate
【钩子函数——预留的扩展】
版权归原作者 孤寒者 所有, 如有侵权,请联系我们删除。