分析forms 组件如何进行校验
为何将校验成功的数据放入 cleaned_data
中
检验失败的数据放入 errors
中
代码示例 :
# 进行校验 is_valid()
if form_data.is_valid():
print(‘校验成功‘)
# 获得校验成功的数据 cleaned_data
print(form_data.cleaned_data)
else:
print(‘检验失败‘)
# 获得检验失败的错误提示 errors
print(form_data.errors)
error = form_data.errors.get(‘__all__‘)
forms组件最核心的就是 is_valid( )
这个校验机制, 也就是我们的突破口
is_valid( )
查看其内部源码def is_valid(self):
"""Return True if the form has no errors, or False otherwise."""
# 如果表单没有错误则返回True,否则返回False
return self.is_bound and not self.errors
也就是说让表单验证成功就必须保证
self.is_bound
为 True ,self.errors
为 False
self.is_bound
查看其源码self.is_bound = data is not None or files is not None
只要数据部位空或者文件不为空,
self.is_bound
就为 True, 也就是只要你传值了就为 True
self.errors
查看源码@property # 类装饰器,可以伪装成属性来使用(不需要加括号)
def errors(self):
"""Return an ErrorDict for the data provided for the form."""
# 为表单提供的数据返回ErrorDict。
if self._errors is None: # 如果_errors中为空则执行full_clean()
self.full_clean()
return self._errors
self._error
self._errors = None # Stores the errors after clean() has been called.
发现其默认就是 None, 也就是说:无论如何都会执行
self.full_clean()
full_clean()
中查看def full_clean(self):
"""
Clean all of self.data and populate self._errors and self.cleaned_data.
"""
# 对所有的self.data、self._errors、self.cleaned_data进行校验
# 这里赋值了一个错误字典用来存放错误字段
self._errors = ErrorDict()
if not self.is_bound: # Stop further processing(停止处理其他规则)
return
# 这个字典用来存正确字段
self.cleaned_data = {}
......
self._clean_fields() # 字段校验和局部钩子方法
self._clean_form() # 全局钩子
self._post_clean()
_clean_fields()
def _clean_fields(self):
# 循环从fields中取出name和field
# fields实质上是一个字典,forms组件的实例化就会自动创建一个fields
# 该字典类内部类似 : {‘name‘:‘name字段对象‘,‘pwd‘:‘pwd字段对象‘}
for name, field in self.fields.items():
......
try:
# 判断是不是文件,是文件则走下面的逻辑
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
# 不是文件则进行这一步,使用规则对象对传入的value进行校验(clean()才是真正的进行校验)
value = field.clean(value)
# 然后将值加到字典中去,不成功则最下面抛出异常,将字段和错误信息加入到错误字典中
self.cleaned_data[name] = value
# 判断是否有‘clean_%s‘格式的一个变量名,也就是我们写的局部钩子函数(解释了为什么钩子函数名要那样写)
if hasattr(self, ‘clean_%s‘ % name):
# 有的话就拿出来执行该钩子函数,得到返回数据
value = getattr(self, ‘clean_%s‘ % name)()
# 将返回的数据添加到字典中,如果出错则也是走下面的except
self.cleaned_data[name] = value
except ValidationError as e:
# 将字段和错误信息加入到错误字典中
# 我们使用raise ValidationError(‘‘)抛出异常,与下面这个方法的效果类似
self.add_error(name, e)
add_error
查看关键信息def add_error(self, field, error):
......
......
if field in self.cleaned_data: # 如果field字段对象在cleaned_data
del self.cleaned_data[field] # 那么就将其从中删除
_clean_form()
def _clean_form(self):
try:
cleaned_data = self.clean() # 直接执行我们定义的全局钩子并拿到返回值
except ValidationError as e:
self.add_error(None, e) # 出错则添加错误信息
else:
if cleaned_data is not None: # 没出错则判断全局钩子的返回值是否为空
self.cleaned_data = cleaned_data # 不是空则原封不动的返回给elf.cleaned_data
上面又将
cleaned_data
赋值回了self.cleaned_data
, 这也是为什么书写全局钩子函数的时候成功必须返回完整的数据, 是因为如果不原封不动的返回元数据, 那么它将是一个不完整的数据
is_vaild( )
作为突破口, 查看 self.is_bound
和 not self.errors
self.errors
是否有值, 有值就是 Falseerrors
里面, 判断 _errors
是否都为空, 如果为空返回 full_clean()
,否则返回_errors
full_clean()
,里面存放_errors
和cleaned_data
这两个字典, 一个存错误字段, 一个存储正确字段full_clean()
里面还存放着forms组件的核心,比如self._clean_fields()
: 用来校验字段_clean_fields()
方法发现内部循环每个字段及字段对象, 而对其真正进行校验的是field.clean(value)
方法_errors
和cleaned_data
这两个字典中_errors
中原文:https://www.cnblogs.com/songhaixing/p/14589352.html