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

每篇前言:

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


关于上篇文章剖析源码的整体流程------画个简单的示意图,大家对着在脑中回忆下:

第一阶段:创建类LoginForm

第二阶段:form = LoginForm()

第三阶段:print(form.pwd)

(StringField和TextInput不止这俩,有多个)

验证流程分析:

此处formdata就携带了前端用户输入的数据。

formdata参数有三种类型,具体取决于传过来的参数以什么方式取值:

python 复制代码
    form = LoginForm(formdata=request.form)   # 值.get('k1')、值.getlist()
    form = LoginForm(data={'k1': 'v1'})       # 值['k1']
    form = LoginForm(obj=对象)                # 值.k1

继续,看form.validate() ------> 分析验证流程:

LoginForm没有validate方法,看父类:

python 复制代码
def validate(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 is not None:
            extra[name] = [inline]   # 把钩子函数放到extra字典中

    return super(Form, self).validate(extra) # 接着调用父类的validate方法

先获取所有每个字段定义的 validate_+字段名 匹配的方法,并保存在extra字典中,再执行父类的validate方法:

python 复制代码
def validate(self, extra_validators=None):
        self._errors = None
        success = True
        for name, field in iteritems(self._fields):  # 循环字段的名称和对象,比如第一个就分别是user和StringField对象
            if extra_validators is not None and name in extra_validators: # 判断该字段是否有钩子函数
                extra = extra_validators[name] # 获取到钩子函数
            else:
                extra = tuple()
            if not field.validate(self, extra): # 执行当前字段对象的validate方法
                success = False
        return success

该方法主要用于和需要验证的字段进行匹配(并且携带上每个字段的钩子函数),执行每个字段对象的validate方法:

python 复制代码
def validate(self, form, extra_validators=tuple()):
        self.errors = list(self.process_errors)
        stop_validation = False

        # Call pre_validate
        try:
            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 = True
        except ValueError as e:
            self.errors.append(e.args[0])

        # Run validators
        if not stop_validation:     
            chain = itertools.chain(self.validators, extra_validators)     # 链接字段中的validators和validate_+字段名 验证
            stop_validation = self._run_validation_chain(form, chain)  # 执行每一个验证规则,self.validators先执行

        # Call post_validate
        try:
            self.post_validate(form, stop_validation)
        except ValueError as e:
            self.errors.append(e.args[0])

        return len(self.errors) == 0

在该方法中,先会执行内部预留给用户自定义的字段的pre_validate方法,

再将字段中的验证规则(validators也就是我们定义的validators=[validators.DataRequired()],)和钩子函数(validate_+'字段名')拼接在一起执行,

注意这里的validators先执行而字段的钩子函数后执行,继续来看怎么执行的:

python 复制代码
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])   # 如果有错误,追加到整体错误中
                return True
            except ValueError as e:
                self.errors.append(e.args[0])

        return False

很明显就是循环每一个验证规则,并执行,有错误追加到整体错误中,接着我们回到validate方法中,接着又会执行post_validate,这也是内置钩子函数,允许用户自己定义,最后这个字段的数据验证完成了,而在开始的for循环,循环结束意味着整个验证过程结束。

python 复制代码
def post_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【钩子函数------预留的扩展】
相关推荐
自在的LEE7 分钟前
当 Go 遇上 Windows:15.625ms 的时间更新困局
后端·kubernetes·go
是我知白哒12 分钟前
lxml提取某个外层标签里的所有文本
前端·爬虫·python
测试老哥22 分钟前
Python自动化测试图片比对算法
自动化测试·软件测试·python·测试工具·程序人生·职场和发展·测试用例
爱数学的程序猿23 分钟前
Python入门:1.Python介绍
开发语言·python
繁川1 小时前
深入理解Spring AOP
java·后端·spring
檀越剑指大厂2 小时前
【Python系列】Python中的`any`函数:检查“至少有一个”条件满足
开发语言·python
程序员黄同学3 小时前
如何使用 Python 连接 MySQL 数据库?
数据库·python·mysql
I_Am_Me_3 小时前
【JavaEE初阶】线程安全问题
开发语言·python
张叔zhangshu3 小时前
TensorFlow 的基本概念和使用场景
人工智能·python·tensorflow
运维&陈同学3 小时前
【Elasticsearch05】企业级日志分析系统ELK之集群工作原理
运维·开发语言·后端·python·elasticsearch·自动化·jenkins·哈希算法