exclude_unset VS exclude_none(FastAPI PATCH高频坑)
先记住核心结论:
- exclude_unset=True :剔除前端没传的字段(PATCH首选)
- exclude_none=True :剔除值为None的字段
1. 概念拆解
假设模型
python
from pydantic import BaseModel
from typing import Optional
class ArticleUpdate(BaseModel):
title: Optional[str] = None
content: Optional[str] = None
前端请求体:{"title": null}
① model_dump(exclude_unset=True)
只过滤请求里没有提交的字段
- 前端传了
title: null→ 属于主动提交 ,会保留{"title": None} - 前端没传
content→ 直接删掉
输出结果:
python
{"title": None}
② model_dump(exclude_none=True)
过滤所有值等于None 的字段,不管前端有没有传
前端传 {"title": null}
输出结果:
python
{}
2. 场景对比(重点!)
原有数据库数据:
title="旧标题", content="旧内容"
场景A:PATCH 局部更新(正常业务需求)
需求:只更新前端传过来的字段,不传的不动
推荐:exclude_unset=True
- 前端传
{"title":"新标题"}
→ 更新title,content保留原值 ✅ - 前端传
{"title": null}
→ 后端收到,把title更新为null(业务允许清空标题时使用)
这就是你代码里标准写法!
场景B:如果你误用 exclude_none=True
前端发送 {"title": null} 想清空标题
最终拿到空字典,数据库标题不会被清空,出现隐性bug。
3. 一张表看懂区别
| 配置 | 规则 | 前端传 {"title":null} |
前端不传title |
|---|---|---|---|
| exclude_unset=True | 删掉未传入字段 | {"title": None} |
移除title |
| exclude_none=True | 删掉值为None字段 | {} |
移除title |
4. 终极开发规范
- PATCH 局部更新 → 固定用 exclude_unset=True
python
update_data = article.model_dump(exclude_unset=True)
- 什么时候用 exclude_none?
极少场景:允许前端传null,但你不想把null写入数据库,主动忽略null字段。
业务上不推荐,需要清空字段就正常让它更新为null,逻辑清晰。
5. 拓展:容易混淆的第三个参数
exclude_defaults=True
剔除等于字段默认值 的数据。
比如字段默认 None,效果近似exclude_none,但触发逻辑不一样,日常PATCH几乎不用。
6. 经典踩坑案例
很多新手写PATCH错误写法:
python
# ❌ 错误
article.model_dump(exclude_none=True)
前端想清空标题 {"title":null},结果更新失效,找bug很久。