Django Form 和 ModelForm 有什么用?和 DRF Serializer 有什么区别?
简化版
Django Form 用于表单数据校验和清洗,ModelForm 能根据 Model 自动生成字段并保存模型;DRF Serializer 更偏 API 场景,用于请求数据校验、对象序列化和反序列化。Form 面向 HTML 表单,Serializer 面向 REST API。
详细版
Form 的核心是 is_valid()、cleaned_data 和错误收集。ModelForm 在此基础上绑定模型,减少重复字段定义。
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ["name", "email"]
DRF Serializer 则把模型或普通对象转换成 JSON 友好的结构,也能把请求 JSON 校验后变成可保存数据。面试要说清:它们都能校验,但入口、输出和使用场景不同。
完整版教学
一、为什么需要 Form
用户输入永远不可信。HTML 表单提交过来的值都是字符串,还可能缺字段、乱填格式、绕过前端校验。Form 把字段声明、类型转换、校验错误统一起来。
request.POST -> Form -> is_valid -> cleaned_data/errors
这比在 view 里手写一堆 if 更可维护。
二、Form 的校验流程
Form 会先做字段级转换和校验,再执行 clean_<field>(),最后执行整体 clean()。通过后数据进入 cleaned_data。
class LoginForm(forms.Form):
username = forms.CharField(max_length=30)
password = forms.CharField(min_length=8)
| 阶段 | 作用 |
|---|---|
| 字段转换 | 字符串转目标类型 |
| 字段校验 | 必填、长度、格式 |
clean_xxx | 单字段业务校验 |
clean | 跨字段校验 |
三、ModelForm 的价值
ModelForm 根据 Model 字段生成表单,避免模型字段和表单字段写两遍。适合后台管理、CRUD 表单和简单业务录入。
form = UserForm(request.POST)
if form.is_valid():
form.save()
但 ModelForm 不等于可以直接暴露所有字段。必须显式写 fields 或 exclude,避免用户提交不该修改的字段,如 is_admin。
ModelForm 最重要的安全习惯是显式列出允许用户提交的字段。
四、DRF Serializer 解决什么
API 场景里,请求体通常是 JSON,响应也要 JSON。Serializer 负责把复杂对象转成基础类型,也负责把输入数据校验成可用数据。
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "name", "email"]
Serializer 更关注 API 表达、嵌套对象、只读字段、响应输出和反序列化创建更新。
五、Form 和 Serializer 的对比
| 维度 | Form/ModelForm | DRF Serializer |
|---|---|---|
| 主要场景 | HTML 表单 | REST API |
| 输入 | request.POST | JSON/body data |
| 输出 | 表单错误/cleaned_data | JSON/errors/validated_data |
| 保存 | ModelForm.save | Serializer.save |
如果项目是传统模板渲染,用 Form;如果是前后端分离 API,用 Serializer。
六、常见安全边界
不管 Form 还是 Serializer,都要避免让用户控制敏感字段。比如用户资料更新接口不能允许提交 role、is_staff、balance。输出也要避免泄露密码哈希、token 等字段。
输入白名单: 用户能改什么
输出白名单: 用户能看什么
这就是为什么输入模型和输出模型常常要分开。
七、常见误区与追问
- 误区:前端校验了,后端 Form 可以省。 后端必须校验,前端可被绕过。
- 误区:ModelForm 可以用
fields="__all__"。 容易暴露敏感字段,生产中应谨慎。 - 误区:Serializer 只负责输出 JSON。 它也负责输入校验和反序列化。
- 追问:cleaned_data 和 data 区别? cleaned_data 是校验和转换后的可信数据。
- 追问:跨字段校验放哪里? Form 的
clean()或 Serializer 的validate()。 - 追问:ModelForm 和 ModelSerializer 像吗? 思路类似,都能基于模型生成字段,但服务场景不同。
- 追问:如何处理只读字段? Serializer 里用
read_only_fields或显式字段配置。
八、加强记忆
Form 记成“HTML 表单校验器”,ModelForm 是“表单到模型的快捷桥”,DRF Serializer 是“API 输入输出契约”。它们都能校验,但服务对象不同。面试回答时抓住输入来源、输出形态、保存方式和字段白名单,就能说清边界。