组合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
相关产品推荐
相关产品推荐

