
Pydantic V2 不再支持重写 dict() 方法实现递归序列化增强,但可通过 @computed_field 结合 model_dump() 实现等效效果,使嵌套模型自动携带类名等元信息。
pydantic v2 不再支持重写 `dict()` 方法实现递归序列化增强,但可通过 `@computed_field` 结合 `model_dump()` 实现等效效果,使嵌套模型自动携带类名等元信息。
在 Pydantic V1 中,开发者常通过重写 BaseModel.dict() 方法,在序列化时动态注入元数据(如 __name__),且因 dict() 会递归调用子模型的同名方法,该行为天然支持嵌套结构。然而,V2 彻底移除了 dict()/json() 等旧接口,统一使用 model_dump() 和 model_dump_json(),且其内部不再触发用户自定义的 dict() 方法——这意味着直接继承并覆写已失效。
所幸,Pydantic V2 提供了更声明式、更安全的替代方案:@computed_field。它允许你将任意属性声明为运行时计算的字段,并可指定 alias 控制序列化键名。关键在于:该字段会被 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))
输出结果为:
{
"__name__": "Bar",
"whenever": 3.14,
"foo": {
"__name__": "Foo",
"whatever": 123
}
}
✅ 优势说明:
-
@computed_field是声明式设计,语义清晰,与 Pydantic 的验证和序列化机制深度集成; -
by_alias=True确保alias(如"__name__")被实际使用; - 所有嵌套模型(如
foo: Foo)只要继承BaseModel2,就会自动包含__name__字段,实现真正递归生效。
⚠️ 注意事项:
- 不要尝试在 V2 中复用 V1 的
dict()覆写方式——它不会被model_dump()调用,属于无效代码; - 若需更复杂逻辑(如动态添加字段、条件序列化),可结合
model_serializer装饰器定制整个模型的序列化流程; -
@computed_field默认不参与验证,仅用于序列化输出;若需校验其值,应配合field_validator或在@property内部手动抛出异常。
总之,@computed_field + model_dump(by_alias=True) 是 Pydantic V2 中实现“递归注入序列化元信息”的标准、推荐且健壮的方式。










