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

Pydantic父类类型字段传入子类实例时model_dump()无法获取数据

问题描述

我想用自定义__repr__方法生成对象的易读输出,同时希望将字段类型声明为父类,确保传入该字段的所有子类实例都能通过验证。但发现只有在字段定义中显式声明为子类类型时,repr方法里的self.model_dump()才能正常获取子类数据;如果用父类类型声明字段,model_dump()只会返回空字典,无法拿到子类的字段内容。

可正常运行代码(显式声明字段类型)

from pydantic import BaseModel, Field
from pydantic.config import ConfigDict


class QueryParams(BaseModel):
    pass


class subQueryParams(QueryParams):
    test: str = "test"


class YourModel(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)
    command_params: subQueryParams = Field()

    def __repr__(self) -> str:
        """Human readable representation of the object."""
        items = [
            f"{k}: {v}"[:83] + ("..." if len(f"{k}: {v}") > 83 else "")
            for k, v in self.model_dump().items()
        ]
        return f"{self.__class__.__name__}\n\n" + "\n".join(items)

YourModel(command_params=subQueryParams())

返回结果:

YourModel

command_params: {'test': 'test'}

异常代码(字段类型改为父类)

from pydantic import BaseModel, Field
from pydantic.config import ConfigDict


class QueryParams(BaseModel):
    pass


class subQueryParams(QueryParams):
    test: str = "test"


class YourModel(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)
    command_params: QueryParams = Field()

    def __repr__(self) -> str:
        """Human readable representation of the object."""
        items = [
            f"{k}: {v}"[:83] + ("..." if len(f"{k}: {v}") > 83 else "")
            for k, v in self.model_dump().items()
        ]
        return f"{self.__class__.__name__}\n\n" + "\n".join(items)


YourModel(command_params=subQueryParams())

返回结果:

YourModel

command_params: {}

问题

如何在使用父类类型声明字段的同时,得到第一个代码示例中的理想输出?

临时解决方案

def __repr__(self) -> str:
        """Human readable representation of the object."""
        items = [
            f"{k}: {v}"[:83] + ("..." if len(f"{k}: {v}") > 83 else "")
            for k, v in self.model_dump().items()
        ]

        # 提取子类数据
        if self.command_params:
            add_item = self.command_params.model_dump()
        for i, item in enumerate(items):
            if item.startswith('command_params:'):
                items[i] = f'command_params: {add_item}'
                break  # 假设只有一个command_params字段,更新后停止


        return f"{self.__class__.__name__}\n\n" + "\n".join(items)

最优解决方案

方法1:修改父类配置,允许额外字段

在父类QueryParams中添加extra='allow'配置,让父类可以接受并序列化子类的所有额外字段:

from pydantic import BaseModel, Field
from pydantic.config import ConfigDict

class QueryParams(BaseModel):
    model_config = ConfigDict(extra='allow')

class subQueryParams(QueryParams):
    test: str = "test"

class YourModel(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)
    command_params: QueryParams = Field()

    def __repr__(self) -> str:
        items = [
            f"{k}: {v}"[:83] + ("..." if len(f"{k}: {v}") > 83 else "")
            for k, v in self.model_dump().items()
        ]
        return f"{self.__class__.__name__}\n\n" + "\n".join(items)

# 运行测试
print(YourModel(command_params=subQueryParams()))

运行后会输出:

YourModel

command_params: {'test': 'test'}

方法2:直接序列化实际对象

如果不想修改父类配置,可以在__repr__中直接对字段的实际对象进行序列化,而不是依赖self.model_dump()的结果:

from pydantic import BaseModel, Field
from pydantic.config import ConfigDict

class QueryParams(BaseModel):
    pass

class subQueryParams(QueryParams):
    test: str = "test"

class YourModel(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)
    command_params: QueryParams = Field()

    def __repr__(self) -> str:
        items = []
        for attr_name, attr_value in self.__dict__.items():
            # 对Pydantic模型对象单独序列化
            if isinstance(attr_value, BaseModel):
                serialized_value = attr_value.model_dump()
            else:
                serialized_value = attr_value
            item_str = f"{attr_name}: {serialized_value}"
            # 处理过长内容
            if len(item_str) > 83:
                item_str = item_str[:83] + "..."
            items.append(item_str)
        return f"{self.__class__.__name__}\n\n" + "\n".join(items)

# 运行测试
print(YourModel(command_params=subQueryParams()))

这种方法不受字段声明类型的限制,会直接序列化对象的实际内容,同样能得到正确结果。


内容的提问来源于stack exchange,提问作者JJ Fantini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:05:41