钩子函数(hook)的使用
在源码中:
form_obj.is_valid()都干了什么?
1.self._errors = ErrorDict() --> {}
2.self.cleaned_data = {}
3.self.fields.items()
字段名 字段对象
4.如果有错误:
self._errors["name"] = ""
5.没有报错:
self.cleaned_data["name"] = value(用户填写的值)
一 简介 我们来聊聊如何构建forms的钩子
二 目的 实现自定义的验证机制,从而进行处理
三 分类:
1 局部钩子 clean_column() 当字段校验完毕后,再进行查找是否有以clean_开头的函数名,如果有,就调用该函数
2 全局钩子 clean() 其原理是对校验完毕的字段,再进行字段间的校验。当字段校验完毕,查找是否有clean的函数,如果有就运行该函数
执行顺序 局部钩子 全局钩子
from django.core.exceptions import ValidationError # 定义局部钩子,用来校验name字段 def clean_name(self): name = self.cleaned_data.get("name", None) value = models.UserInfo.objects.filter().values_list("name") if name in value: raise ValidationError("此名字已经被注册!") else: return name # 定义全局钩子,用来检验密码和确认密码字段是否一致 # 重写父类的clean方法 def clean(self): # 此时 通过校验的字段的数据都保存在 self.clean_data pwd = self.cleaned_data.get("pwd") re_pwd = self.cleaned_data.get("re_pwd") if pwd == re_pwd: return self.cleaned_data else: self.add_error("re_pwd", ValidationError("两次的密码不一致!")) raise ValidationError("两次密码不一致!")
注意
1 单个字段只能指定单个方法
2 钩子是按照顺序执行的,如果上面的不过,直接抛出异常了.不会执行下面的钩子
3 clean()的优先级最高
小补充~~~~~
1.对于多余的字段不存入库,可以采用字典删除的方式入库
forms.cleaned_data.pop("column")
models.object.create(** forms.cleaned_data)
2. 重新父类init 方法
# 重写父类的init方法 def __init__(self, *args, **kwargs): # 1. 批量添加样式 super().__init__(*args, **kwargs) for field in iter(self.fields): self.fields[field].widget.attrs.update({ 'class': 'form-control' }) # 2.form对象是一个可迭代的对象 # choices的数据如果从数据库获取可能会造成数据无法实时更新 # 通过构造方法,在构造中重新获取数据库中的值 self.fields["city"].widget.choices = models.City.objects.all().values_list("id", "name")