给字段加 validators 就能保证数据库里的值合法吗?不能。这篇验证校验器在 save()、full_clean()、ModelForm 里分别运行不运行,以及自定义校验器怎么写才规范。
save() 成功,库里存了: ROOT!!! 999 (既违反正则也违反 MaxValue,save() 没有检查)
full_clean() → {'name': ['letters'], 'age': ['max_value']}Django 认为「校验」是表单/序列化层的事,模型层只提供 full_clean() 让你主动调用。所以通过 shell、管理命令、objects.create() 写入的数据不会被校验器挡住。真正的数据完整性要靠数据库约束(CheckConstraint、UniqueConstraint,本文没有测)。
run_validators('root') 全部错误: [('reserved', '用户名 root 被保留')]
run_validators('ROOT12345') 全部错误: [('letters', '只能小写字母'), ('max_length', 'Ensure this value has at most 8 characters (it has 9).')]
age=200: [('max_value', {'limit_value': 150, 'show_value': 200, 'value': 200})]
name 字段的 validators 列表(自定义 + 自动加入的 max_length): ['not_forbidden', 'RegexValidator', 'MaxLengthValidator']一个校验器抛 ValidationError 后,同字段的其它校验器仍会执行,所有错误合并返回。
is_valid() = False
{'name': ['letters'], 'age': ['max_value']}
表单字段自带的校验器: []full_clean(): {'name': ['unique']}
save() 直接: IntegrityErrorModelForm 把模型校验接进了表单校验。validate_unique 先查再写,两个并发请求仍可能都通过,最终由数据库的唯一约束拒绝其中一个(第 35 篇)。
deconstruct(): ('__main__.MaxWords', (3,), {})
校验: max_words {'n': 2}校验器实例要能比较相等(__eq__)并可序列化,否则每次 makemigrations 都会认为字段变了。