
pydantic 提供了 `exclude_defaults=true` 参数,可在调用 `model_dump()` 时跳过所有使用默认值初始化的字段,从而实现 json 序列化时不包含默认值,兼顾数据简洁性与模型一致性。
在构建 API 响应、配置导出或前端通信等场景中,避免将未显式设置的默认字段写入 JSON 是一种常见需求——它能减小载荷体积、提升可读性,并减少客户端对冗余字段的处理逻辑。
Pydantic v2(推荐使用)已弃用旧版 json() 方法和 default=pydantic_encoder 的手动 JSON 序列化方式,转而推荐使用更灵活、语义清晰的 model_dump() 和 model_dump_json() 方法。
✅ 正确做法:使用 model_dump(exclude_defaults=True)
以下为适配你原始示例的优化写法(Pydantic v2+):
import json
from typing import List
from pydantic import BaseModel, Field
class Animal(BaseModel):
name: str
legs: int
tails: int = 1 # 默认值为 1
class AnimalList(BaseModel):
animals: List[Animal]
# 构造实例:dog 未显式传 tails → 使用默认值;human 显式设为 0
animals = AnimalList(animals=[
Animal(name='dog', legs=4),
Animal(name='human', legs=2, tails=0)
])
# ✅ 序列化时自动排除默认值字段(如 dog.tails=1 不输出)
dumped = animals.model_dump(exclude_defaults=True)
j = json.dumps(dumped, indent=2)
print(j)输出结果符合预期:
{
"animals": [
{"name": "dog", "legs": 4},
{"name": "human", "legs": 2, "tails": 0}
]
}? 补充说明:exclude_defaults 的行为逻辑
- 仅排除字段定义中声明的默认值(如 tails: int = 1 或 tails: int = Field(default=1)),不依赖运行时值是否“等于”默认值;
- 若字段为 Optional 或 Union 类型且值为 None,exclude_defaults=True 不会自动排除该字段(除非显式设为 Field(default=None, exclude=True));
- 对嵌套模型(如 AnimalList 包含 Animal)递归生效。
? 进阶建议:用 Field(default=...) + None 实现语义更清晰的“可选字段”
若业务上希望 tails 是真正可选的字段(即缺失时视为“未提供”,而非“使用默认值”),更推荐如下建模方式:
class Animal(BaseModel):
name: str
legs: int
tails: int = Field(default=1, exclude=True) # 或配合 exclude_defaults 更自然
# 更推荐:tails: Optional[int] = None # 并在逻辑中处理 None → 1但注意:若你后续需反序列化 JSON 并重建对象(如 AnimalList(**json.loads(j))),使用 exclude_defaults=True 生成的 JSON 仍能正确还原——因为 Pydantic 在实例化时会自动填充缺失的默认值字段,无需额外干预。
✅ 总结
- ✅ 优先使用 model_dump(exclude_defaults=True) 替代手动 json.dumps(..., default=...);
- ✅ 确保使用 Pydantic v2+(BaseModel.model_dump() 是标准接口);
- ⚠️ 避免混淆 exclude_defaults 与 exclude_unset:后者仅排除未在初始化时传入的字段(即使有默认值),而 exclude_defaults 排除所有值等于定义默认值的字段;
- ? 如需细粒度控制(如仅对某字段启用),可用 Field(exclude=True) 或 model_dump(exclude={'tails'})。
通过合理使用 exclude_defaults,你能在保持模型强类型优势的同时,输出更精简、语义更准确的序列化数据。










