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

组合Pydantic BaseModel时自定义JSON编码器失效问题

解决Pydantic嵌套模型自定义序列化失效问题

在Pydantic 1.10版本中,定义嵌套BaseModel时会遇到以下问题:子模型的json_encoders自定义序列化逻辑在父模型序列化时失效——单独序列化子模型Asd时,time字段能正确序列化为YYYY-MM-DD格式,但序列化包含Asd的父模型Lol时,time字段会回到默认的ISO格式(如2020-01-01T00:00:00)。

问题原因

Pydantic 1.x中,父模型序列化嵌套子模型时,默认不会继承子模型的json_encoders配置,而是使用全局默认的类型序列化规则,导致子模型的自定义编码器不生效。


方案一:使用@field_serializer字段级序列化(推荐)

@field_serializer是Pydantic 1.9+引入的字段专属序列化装饰器,定义在子模型中的字段序列化逻辑会在任何场景下生效(包括嵌套),无需修改父模型:

from datetime import datetime
from pydantic import BaseModel, field_serializer

class Asd(BaseModel):
    time: datetime

    # 给time字段定义专属序列化逻辑
    @field_serializer('time')
    def serialize_time(self, dt: datetime) -> str:
        return dt.strftime("%Y-%m-%d")

class Lol(BaseModel):
    asd: Asd

# 测试验证
asd = Asd(time=datetime.strptime("2020-01-01 00:00:00", "%Y-%m-%d %H:%M:%S"))
print(Lol(asd=asd).json())
# 输出:{"asd": {"time": "2020-01-01"}}

方案二:父模型继承子模型的json_encoders

如果坚持使用json_encoders配置,可以将子模型的编码器规则复制到父模型的Config中,避免重复代码:

from datetime import datetime
from pydantic import BaseModel

class Asd(BaseModel):
    time: datetime
    
    class Config:
        json_encoders = {datetime: lambda dt: dt.strftime("%Y-%m-%d")}

class Lol(BaseModel):
    asd: Asd
    
    class Config:
        # 继承Asd的json_encoders配置
        json_encoders = Asd.Config.json_encoders.copy()

# 测试验证
asd = Asd(time=datetime.strptime("2020-01-01 00:00:00", "%Y-%m-%d %H:%M:%S"))
print(Lol(asd=asd).json())
# 输出:{"asd": {"time": "2020-01-01"}}

方案三:父模型中自定义嵌套字段的序列化

在父模型中给嵌套字段asd定义序列化逻辑,直接调用子模型的序列化结果:

from datetime import datetime
from pydantic import BaseModel, field_serializer

class Asd(BaseModel):
    time: datetime
    
    class Config:
        json_encoders = {datetime: lambda dt: dt.strftime("%Y-%m-%d")}

class Lol(BaseModel):
    asd: Asd

    @field_serializer('asd')
    def serialize_asd(self, asd_obj: Asd) -> dict:
        # 调用子模型的dict()方法,应用其自定义序列化规则
        return asd_obj.dict()

# 测试验证
asd = Asd(time=datetime.strptime("2020-01-01 00:00:00", "%Y-%m-%d %H:%M:%S"))
print(Lol(asd=asd).json())
# 输出:{"asd": {"time": "2020-01-01"}}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:56:25