django form 严格验证依赖字段类型、clean_字段名() 钩子和is_valid()后仅取cleaned_data:字段类型强制基础校验,clean_字段名()处理业务逻辑并返回值,is_valid()失败时cleaned_data为空,必须先校验再取值。

直接上结论:Django Form 的严格验证不靠“加开关”,而靠三件事——字段类型选对、clean_字段名() 钩子写实、is_valid() 后只从 cleaned_data 取值。漏掉任意一环,所谓“严格”就形同虚设。
字段类型决定基础校验边界
Django 字段自带默认规则,不是装饰,而是强制约束。比如 EmailField 不只是提示“请输入邮箱”,它会在调用 is_valid() 时真正执行 RFC 5322 兼容的正则匹配;IntegerField 会拒绝 "123abc" 或空字符串,哪怕你没写任何额外逻辑。
-
CharField(max_length=20):前端没限制?没关系,后端会截断或报错(取决于strip和empty_value设置) -
URLField(verify_exists=False):注意,默认不连网络校验,如需真实可达性检查,得自己重写clean_url() -
BooleanField(required=True):它不接受"false"字符串或空值,只认 Python 的True/False—— 前端 checkbox 没勾就根本不会提交该字段,所以常配合required=False+ 自定义钩子处理
clean_字段名() 是唯一可控的自定义入口
内置校验管长度、格式、必填,但管不了业务逻辑。比如“密码和确认密码必须一致”“用户名不能与邮箱前缀相同”——这些必须塞进 clean_字段名() 方法里。
- 方法名必须严格为
clean_+ 字段变量名(如字段是password2,方法就得叫clean_password2) - 必须返回处理后的值(哪怕原样返回),否则字段在
cleaned_data中消失 - 抛异常要用
ValidationError,不要用ValueError,否则错误进不了form.errors - 跨字段校验(如比对两个密码)要写
clean()方法,而不是clean_字段名(),因为后者拿不到其他字段的cleaned_data
示例:clean_email() 中查库判断是否已注册:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise ValidationError("该邮箱已被注册")
return email.lower().strip() # 统一转小写+去空格
is_valid() 不通过,cleaned_data 就是空字典
这是最容易踩的坑:很多人在 if form.is_valid(): 外直接访问 form.cleaned_data,结果得到 {} 还以为数据丢了。Django 设计就是如此——验证失败,cleaned_data 不生成,只留 form.errors。
- 永远先判
if form.is_valid():,再取cleaned_data -
form.errors是ErrorDict,可转 JSON:form.errors.as_json(),适合 API 返回 - 模板里用
{{ form.email.errors }}渲染单字段错误,{{ form.non_field_errors }}渲染clean()抛出的全局错误 - 别在视图里手动拼
request.POST.get("xxx"),那等于绕过整个 Form 验证体系
ModelForm 的验证链容易被忽略
如果你用 ModelForm,验证实际分三层:字段级 → clean_字段名() → clean() → _post_clean()(触发模型 full_clean())。最后一层会跑模型层的 validators 和 unique_together 等约束。
- 模型字段设了
unique=True,但没在ModelForm的Meta.fields里显式列出该字段?那这个唯一性校验不会触发 -
ModelForm实例化时传instance=xxx,更新操作下,unique校验会自动排除当前实例,避免误报 - 想跳过模型层校验(比如导入数据时临时容忍脏数据),得手动调
form.save(commit=False),再绕过model_instance.full_clean()
真正严格的验证,从来不是堆砌配置项,而是理解每一步数据流在哪被拦截、谁负责抛错、错误最终落到哪——漏掉任一环节,攻击者就可能从缝隙里挤进来。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










