
Pydantic V2 不再支持直接重写 dict() 方法,但可通过 @computed_field 结合 model_dump() 实现等效的递归序列化增强,自动为所有嵌套模型实例注入元信息(如类名)。
pydantic v2 不再支持直接重写 `dict()` 方法,但可通过 `@computed_field` 结合 `model_dump()` 实现等效的递归序列化增强,自动为所有嵌套模型实例注入元信息(如类名)。
在 Pydantic V1 中,开发者常通过重载 BaseModel.dict() 方法实现序列化逻辑的全局增强(例如自动添加 __name__ 字段),且该逻辑会自然递归作用于嵌套子模型。但在 V2 中,dict() 已被弃用,统一由 model_dump() 取代,且其底层不再调用模型实例的方法——这意味着单纯重写 model_dump() 或自定义方法无法自动递归生效。
不过,V2 提供了更规范、更安全的替代方案:使用 @computed_field 定义只读计算字段,并配合 by_alias=True 参数,即可在序列化结果中稳定注入元数据,且该字段会随 model_dump() 递归遍历自动包含在所有层级的嵌套模型中。
以下是一个完整示例:
from typing import Optional
from pydantic import BaseModel, computed_field
class BaseModel2(BaseModel):
@computed_field(alias="__name__")
@property
def name(self) -> str:
return self.__class__.__name__
class Foo(BaseModel2):
whatever: int
class Bar(BaseModel2):
whenever: Optional[float] = 1.1
foo: Foo
m = Bar(whenever=3.14, foo=Foo(whatever=123))
print(m.model_dump(by_alias=True))
输出结果为:
{
"whenever": 3.14,
"foo": {
"whatever": 123,
"__name__": "Foo"
},
"__name__": "Bar"
}
✅ 关键要点说明:
-
@computed_field(alias="__name__")确保字段在序列化时以__name__键名出现; -
@property保证字段惰性计算、无副作用,符合 Pydantic 的序列化语义; -
model_dump(by_alias=True)是必需的,否则alias不生效; - 因
model_dump()默认递归处理嵌套BaseModel实例,父类中定义的computed_field会自动应用于所有子模型(如Foo和Bar),实现真正意义上的“递归增强”。
⚠️ 注意事项:
- 不要尝试重写
model_dump()—— 它是高度优化的 C 层封装,手动覆盖易破坏验证、排除逻辑(如exclude/include)及性能; - 若需条件性注入(如仅开发环境),可在
@property中加入os.getenv()或配置判断,但应避免 I/O 或复杂计算; -
computed_field在model_validate()或model_construct()时不会被反向解析,因此该字段纯属序列化增强,不影响反序列化行为。
综上,computed_field + by_alias=True 是 Pydantic V2 中实现可递归、可继承、可维护的序列化增强的最佳实践。










