1、从is_valid方法入手

    def is_valid(self):
    """Return True if the form has no errors, or False otherwise."""
    return self.is_bound and not self.errors

    如果is_valid要返回True的话,那么self.is_bound要为True并且self.errors要为Flase(字面意思上看errors为False的话,表示没有错误信息)

  2、is_bound

    以下代码出现在BaseForm类中,也就是Form的父类(Form继承了父类的初始化方法)

    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
     initial=None, error_class=ErrorList, label_suffix=None,
    empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None):
    self.is_bound = data is not None or files is not None

    is_bound为True的条件是data不为None,或者files不为None

    也就是说在初始化一个Form对象时,只要传入了data或者files,那么is_bound的属性就一定为True

    在调用is_valid方法校验数据之前,肯定需要将POST提交的数据用来初始化一个Form对象,然后调用该方法对数据进行校验

    所以,只要是用来校验POST提交的数据时,is_bound肯定为True    

      form_obj = RegForm(request.POST)  # 包含用户提交的数据的From对象
      if form_obj.is_valid(): # 对数据进行校验
      return HttpResponse('ok')

  3、errors

    @property
    def errors(self):
    """Return an ErrorDict for the data provided for the form."""
    if self._errors is None:
    self.full_clean()
    return self._errors

    errors实际上是一个方法,只是使用property装饰器装饰成了属性,可以通过对象.属性名的方式调用

    当self._errors为None时会执行,full_clean方法。然后最终返回_errors。

    _errors同样定义在BaseForm的初始化方法内,初始化即为None,但是最终返回却将它作为结果返回。

    那么,说明full_clean内部肯定对_errors做了修改

    直接看full_clean方法内部做了些什么

  4、full_clean() 

    def full_clean(self):
    """
    Clean all of self.data and populate self._errors and self.cleaned_data.
    """
    self._errors = ErrorDict() # 错误字典(初始化为空字典)
    if not self.is_bound: # Stop further processing.
    return
    self.cleaned_data = {} # 创建了cleaned_data字典,用于后续存放结果校验无误的数据
    # If the form is permitted to be empty, and none of the form data has
    # changed from the initial data, short circuit any validation.
    if self.empty_permitted and not self.has_changed():
    return

    self._clean_fields()
    self._clean_form()
    self._post_clean()

    该方法首先赋值了一个错误字典给_errors(前面提到,初始化时为None),也就是说再经过一系列校验后,如果最后该字典为空,那么说明没有错误,即校验通过。

    接着往下看。

    如果is_bound为False直接终止方法执行,也就是该Form对象内没有数据,不需要校验。

    然后创建了一个字典cleaned_data,用于存放后续校验无误的数据。

    从这就可以知道,一个form对象只有在使用了is_valid()方法后,内部才会生成cleaned_data字典。使用is_valid()之前没有该变量。

    然后接着看后续调用校验方法的过程。

  5、_clean_fields() 

    def _clean_fields(self):
    for name, field in self.fields.items():
    # value_from_datadict() gets the data from the data dictionaries.
    # Each widget type knows how to retrieve its own data, because some
    # widgets split data over several HTML fields.
    if field.disabled:
    value = self.get_initial_for_field(field, name)
    else:
    value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
     try:
    if isinstance(field, FileField):
    initial = self.get_initial_for_field(field, name)
    value = field.clean(value, initial)
    else:
    value = field.clean(value)
    self.cleaned_data[name] = value
    if hasattr(self, 'clean_%s' % name):
    value = getattr(self, 'clean_%s' % name)()
    self.cleaned_data[name] = value
    except ValidationError as e:
    self.add_error(name, e) # 将捕获到的异常添加到错误字典中

    该方法内部,直接对fields进行迭代取值处理。

    fields内部存放的就是表单提交的数据,以字典形式存放,name对应的就是Form类中定义的属性名,field就是一个字段对象。

    如果当前迭代到的字段对象对应的input被禁用的话(disableed为True),那么就以该input的初始值作为该字段的值(initial设置的值。如果没有设置,得到的则是空字符串)。

    反之,该字段的值就是用户输入的值。

    

    接着,判断当前迭代到的字段对象类型,如果是文件类型,则使用文件相关的校验方式

    其他类型,都使用else代码块里的校验方式

    def clean(self, value):
    """
    Validate the given value and return its "cleaned" value as an
    appropriate Python object. Raise ValidationError for any errors.
    """
    value = self.to_python(value)
    self.validate(value)
    self.run_validators(value)
    return value

    validate(value)方法,即校验当前字段的值是否为空,如果为空则抛出required的提示信息(字段为必填项时会进行该校验)

    run_validators方法,执行的是当前字段默认的校验器(如果是Email字段,则它的默认校验器就会校验字段的值是否符合正确的邮箱格式)以及自定义的校验器(即设置字段的参数validators时,传入的自定义的校验函数对象)

    如果校验过程中出现异常,会层层抛出,每一层都在捕获异常,最终会将捕获到的异常添加到错误字段中。

    except ValidationError as e:
    self.add_error(name, e)

    然后最终返回原值。如果上述校验无误,则将该值添加到cleaned_data字典内。

    接着,判断有没有该字段的局部钩子函数,对该字段进行校验。

    有的话,就调用这个局部钩子就要该字段的值,校验无误就将该值重新赋值一遍给cleaned_data。出现异常就会抛出,执行异常处理函数,将错误信息添加到错误字典,并将该字段的值从cleaned_data字典内删除。

    从这也就能知道,局部钩子函数的返回值必须是对应字段的值原样返回,否则即使校验通过,在赋值时也会出错,导致最终得到的值不对。

   总结:

    clean方法主要功能就是执行字段内置校验方法、字段内置校验器以及自定义校验器

    _clean_fields方法只要功能就是执行clean、以及局部钩子函数,对数据进行校验。

  

  6、_clean_form()

    执行全局的钩子函数

    全局钩子函数 ,返回值必须是cleaned_data

    def clean(self):
    """
    Hook for doing any extra form-wide cleaning after Field.clean() has been
    called on every field. Any ValidationError raised by this method will
    not be associated with a particular field; it will have a special-case
    association with the field named '__all__'.
    """
    return self.cleaned_data

    因为,自定义的全局钩子函数,实际上就是重写了上述方法,最终返回值必须和上述方法用于,即校验无误的数据字典

  总结:

    整个is_valid()的主要的流程为:

      1、执行full_clean方法

        先定义一个错误字典用户后续判断校验是否正确,

        还有一个cleaned_data存放后续校验无误的数据

      2、执行_clean_fields方法

        该方法对数据进行除了全局钩子函数以外的校验

        先执行字段内置校验方法、字段内置校验器以及自定义校验器对数据进行校验

        然后执行局部钩子函数对数据进行校验

      3、执行_clean_form方法

        该方法对数据进行全局钩子函数的校验

    所有校验执行的先后顺序:

      字段内置的校验方法——>字段内置校验器——>字段自定义的校验器——>局部钩子函数——>全局钩子函数

  

    

django—Form组件校验方法(is_valid)执行流程的更多相关文章

  1. Python - Django - form 组件校验功能

    app01/models.py: from django.db import models class UserInfo(models.Model): username = models.CharFi ...

  2. python3开发进阶-Django框架中form的查看校验方法is_valid()的源码,自定义验证方法

    form表单的校验方法is_valid() 点开我们发现这个函数里面只有两个方法方法,最终返回True or False 我们点进.is_bound属性,里面判断传输的数据不是空和上传文件不是空 点进 ...

  3. Django---FORM组件.FORM组件的字段,FORM组件校验流程,FORM组件的全局和局部钩子,FORM和Model的组合

    Django---FORM组件.FORM组件的字段,FORM组件校验流程,FORM组件的全局和局部钩子,FORM和Model的组合 一丶FORM的介绍 1.生成页面可用的HTML标签 2.对用户提交的 ...

  4. 9.24 Django Form组件

    2018-9-23 20:10:04 这两天优化了自己图书管理系统 github 连接:https://github.com/TrueNewBee/pythonDemo 顺便整理了博客,写了好多总结, ...

  5. django Form组件

    django Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1.创建 ...

  6. django form组件 cookies,session

    django form组件 渲染标签  就是组件里面的字段在前端展示叫做渲染标签 校验数据  用户输入的数据提交给后端组件叫做校验数据 forms组件中定义的字段都是必须传值的(required=Tr ...

  7. Django form组件 与 cookie/session

    目录 一.form组件 二.cookie.session 返回Django 组件 一.form组件 1.1 以注册功能为例 注册功能 1.渲染前端标签获取用户输入 --> 渲染标签 2.获取用户 ...

  8. 6月28日 Django form组件 和 modelform组件

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...

  9. Django—Form组件

    Django From简介 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比 ...

随机推荐

  1. 【深入理解JVM】学习笔记——-1、JVM基本结构

    转载自:https://blog.csdn.net/singit/article/details/54920387?utm_source=blogkpcl11 什么是jvm?JVM的基本结构, 也就是 ...

  2. 3.Kafka集群配置

  3. 一文带你熟悉JAVA IO这个看似很高冷的菇凉

    Java IO 是一个庞大的知识体系,很多人学着学着就会学懵了,包括我在内也是如此,所以本文将会从 Java 的 BIO 开始,一步一步深入学习,引出 JDK1.4 之后出现的 NIO 技术,对比 N ...

  4. pytest封神之路第五步 参数化进阶

    用过unittest的朋友,肯定知道可以借助DDT实现参数化.用过JMeter的朋友,肯定知道JMeter自带了4种参数化方式(见参考资料).pytest同样支持参数化,而且很简单很实用. 语法 在& ...

  5. dubbo学习(八)dubbo项目搭建--消费者(服务消费者)

    PS:  项目架子以及工程间的maven依赖配置暂时省略,后续看情况可能会单独写一篇文章捋捋框架结构,先马克~ 配置和启动 1.pom文件引入dubbo和zookeeper的操作客户端(此步骤与生产者 ...

  6. 【性能监控-Perfmon工具】手动添加数据收集器,点击保存时需要输入用户NT AUTHORITY\SYSTEM的密码问题

    发现是有的电脑会弹出这种输入用户NT AUTHORITY\SYSTEM密码的现象,有的电脑不会弹出这个对话框.......仍然没搞懂是为什么? 关键是输入windows用户登录时的密码也不对!!压根不 ...

  7. 关于TCP建立连接

    TCP大家大多称之为"三次握手".今天看了一篇文章,学到了"三步握手". TCP建立连接,客户端发送SYN给服务端,服务端接收到请求回应ACK.服务端发送SYN ...

  8. 基于Java反射的定时任务设计

    一.使用场景 1.不需要立即执行.立即得到结果返回. 2.如果执行失败.需要有失败补偿机制. 3.和业务代码解耦,适用于不同的务场景. 4.调用接口的入参.出参 统计,方便查询. 二.执行顺序 1.业 ...

  9. Generator函数在流程控制中的应用

    扯蛋 做了两年的Nodejs全栈开发,不知道为什么跑来做游戏呢(大概是厦门nodejs不好找工作吧).用的是网易的pomelo的游戏框架.现接手了一个棋牌游戏:二十一点,不懂的规则的可以自行百度. 二 ...

  10. react-router 路由切换动画

    路由切换动画 因为项目的需求,需要在路由切换的时候,加入一些比较 zb 的视觉效果,所以研究了一下.把这些学习的过程记录下来,以便以后回顾.同时也希望这些内容能够帮助一些跟我一样的菜鸟,让他们少走些坑 ...