You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pydantic v2中如何用model_dump全局排除嵌套模型的计算字段?

解决Pydantic v2嵌套模型中全局排除computed字段的问题

问题复现

在Pydantic v2中,调用model_dump(exclude={'computed': True})时,仅根模型的computed计算字段会被排除,嵌套子模型中的同名字段仍会被序列化输出,示例代码如下:

from pydantic import BaseModel, computed_field

class SubSystem(BaseModel):
    value: int
    
    @computed_field
    def computed(self) -> int:
        return self.value * 2

class System(BaseModel):
    sub: SubSystem
    value: int
    
    @computed_field
    def computed(self) -> int:
        return self.value * 3

system = System(sub=SubSystem(value=10), value=20)
# 仅排除根模型的computed,子模型的computed仍保留
print(system.model_dump(exclude={'computed': True}))
# 输出: {'sub': {'value': 10, 'computed': 20}, 'value': 20}

解决方案

方法1:使用自定义排除函数(推荐)

Pydantic v2的model_dump方法支持传入函数类型的exclude参数,该函数会遍历所有层级的字段,判断是否需要排除。我们可以定义一个函数,只要字段名是computed就返回True,从而全局排除所有层级的该字段,同时保留exclude_defaults、by_alias等原有参数的功能:

from typing import Any
from pydantic import BaseModel, computed_field

# 定义排除函数
def exclude_all_computed(field_name: str, _: Any) -> bool:
    return field_name == 'computed'

# 模型定义不变
class SubSystem(BaseModel):
    value: int
    
    @computed_field
    def computed(self) -> int:
        return self.value * 2

class System(BaseModel):
    sub: SubSystem
    value: int
    
    @computed_field
    def computed(self) -> int:
        return self.value * 3

system = System(sub=SubSystem(value=10), value=20)
# 调用时传入排除函数,同时可添加其他参数
result = system.model_dump(
    exclude=exclude_all_computed,
    exclude_defaults=True,
    by_alias=False
)
print(result)
# 输出: {'sub': {'value': 10}, 'value': 20}

方法2:自定义BaseModel统一处理

如果你的项目中有大量模型需要全局排除computed字段,可以自定义一个基础模型类,重写model_dump方法,默认添加全局排除computed的逻辑,同时兼容原有参数:

from typing import Any, Dict, Optional
from pydantic import BaseModel, computed_field

class CustomBaseModel(BaseModel):
    def model_dump(
        self,
        *,
        mode: str = 'python',
        include: Optional[Dict[str, Any]] = None,
        exclude: Optional[Dict[str, Any] | callable] = None,
        by_alias: bool = False,
        exclude_unset: bool = False,
        exclude_defaults: bool = False,
        exclude_none: bool = False,
        round_trip: bool = False,
        warnings: bool = True,
    ) -> Dict[str, Any]:
        # 组合排除规则:优先排除computed,再应用用户传入的exclude规则
        def combined_exclude(field_name: str, value: Any) -> bool:
            if field_name == 'computed':
                return True
            # 处理用户传入的exclude规则
            if callable(exclude):
                return exclude(field_name, value)
            elif isinstance(exclude, dict):
                return field_name in exclude
            return False
        
        final_exclude = combined_exclude if exclude is not None else (lambda fn, _: fn == 'computed')
        
        return super().model_dump(
            mode=mode,
            include=include,
            exclude=final_exclude,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
            round_trip=round_trip,
            warnings=warnings,
        )

# 继承自定义基础模型
class SubSystem(CustomBaseModel):
    value: int
    
    @computed_field
    def computed(self) -> int:
        return self.value * 2

class System(CustomBaseModel):
    sub: SubSystem
    value: int
    
    @computed_field
    def computed(self) -> int:
        return self.value * 3

system = System(sub=SubSystem(value=10), value=20)
# 直接调用model_dump即可全局排除computed,同时支持其他参数
result = system.model_dump(exclude_defaults=True)
print(result)
# 输出: {'sub': {'value': 10}, 'value': 20}

说明

  • 方法1更灵活,适合临时或局部场景使用;
  • 方法2适合全局统一配置,减少重复代码;
  • 两种方案都完全保留了model_dump原生参数的功能,不会影响exclude_defaults、by_alias等参数的正常使用。

内容的提问来源于stack exchange,提问作者Maxim Suslov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 12:57:55