
ModelForm 不是“自动生成就完事”,它默认只包含模型里 editable=True 的字段,且不会自动处理外键、多对多、文件上传等关联逻辑——你得手动干预。
ModelForm 基础写法:继承 + 指定模型和字段
最简写法就是继承 forms.ModelForm,在 Meta 里声明 model 和 fields。别漏掉 fields,否则会报 TypeError: ModelForm has no model 或空表单。
常见错误现象:__all__ 看起来省事,但一旦模型加了敏感字段(比如 is_active、created_at),它就会悄悄暴露给用户。
用 fields = [‘title’, ‘content’] 显式列出更安全想排除某些字段?用 exclude = [‘updated_at’],但注意它比 fields 优先级低,二者别共存外键字段默认渲染为 select,选项来自关联模型的 __str__;如果没定义,会显示 "<Model object (1)>" 这种内容
保存时绕不开的两个动作:clean() 和 save()
form.save() 看似一步到位,但它不校验外键对象是否存在、不处理上传文件路径、也不自动设置当前用户——这些都得在视图或 clean() 里补。
使用场景:用户提交博客文章,要自动绑定 author 字段。
别在 clean() 里改 self.instance.author,因为 clean() 只负责字段级校验,不涉及实例状态正确做法是在视图里调用 form.save(commit=False),再赋值,最后 instance.save()如果模型有 FileField,确保表单 enctype="multipart/form-data",否则 request.FILES 为空,form.is_valid() 会返回 False 且无提示
外键和多对多字段的坑:save_m2m() 不是总被调用
当用 commit=False 保存实例后,多对多关系不会自动写入数据库——Django 要求你显式调用 form.save_m2m(),但这个方法只在 form.is_valid() 为 True 且模型确实含 ManyToManyField 时才存在。
容易踩的坑:form.save_m2m() 必须在 instance.save() 之后调用,否则报 ValueError: Cannot set values on a ManyToManyField which specifies an intermediary model(尤其用了 through 模型时)。
检查 hasattr(form, ‘save_m2m’) 再调用,避免 AttributeError外键字段如果设了 blank=True 但没传值,form.cleaned_data 里对应键可能是 None,直接赋值给 instance.foreign_key_field 会触发 IntegrityError多对多字段在 cleaned_data 中是 QuerySet 或列表,不是单个对象,别误当成外键处理
ModelForm 的“自动”只到字段映射这层,业务逻辑、权限控制、关联写入、事务边界,全得你自己托住。哪怕只是加个时间戳或当前用户,也得在视图里亲手塞进去。

评论(0)