如何在Pydantic模型的字典中单独指定字段并实现序列化?
解决方案
你的需求核心是让Pydantic模型支持结构化的字典字段,每个字典键对应特定类型的泛型Trait对象,同时不同角色模型的字典字段可自定义,且保留序列化/反序列化能力。下面是具体实现方式:
1. 保留泛型Trait模型定义
from pydantic import BaseModel, NonNegativeInt, NonNegativeFloat, Field from pydantic.generics import GenericModel from typing import TypeVar, Generic, TypedDict DataT = TypeVar('DataT') class Trait(GenericModel, Generic[DataT]): descript: str value: DataT
2. 为每个角色定义专属的Traits类型(用TypedDict)
TypedDict可以精确指定字典中每个键的类型,完美匹配你“不同类的字典字段选择不同”的需求:
class BarbarianTraits(TypedDict): strength: Trait[NonNegativeInt] height: Trait[NonNegativeFloat] weight: Trait[NonNegativeFloat] class WizardTraits(TypedDict): intelligence: Trait[NonNegativeInt] spells: Trait[NonNegativeInt]
3. 定义角色模型并关联对应Traits类型
在角色模型中,将traits字段指定为对应的TypedDict类型,并设置默认值:
class CharacterBarbarian(BaseModel): id: int name: str = 'Barbarok' traits: BarbarianTraits = Field( default={ 'strength': Trait[NonNegativeInt](descript='the force', value=18), 'height': Trait[NonNegativeFloat](descript='tallness', value=1.8), 'weight': Trait[NonNegativeFloat](descript='width', value=92.1), } ) class CharacterWizard(BaseModel): id: int name: str = 'Supremus' traits: WizardTraits = Field( default={ 'intelligence': Trait[NonNegativeInt](descript='smarts', value=16), 'spells': Trait[NonNegativeInt](descript='number of them', value=4), } )
4. 测试序列化/反序列化
完全符合你期望的使用方式,Pydantic会自动处理字典与模型的转换:
SavedWizard_dict = { 'id': 1234, 'name': "Gandalf", 'traits': { 'intelligence': {'descript': 'smarts', 'value': 20}, 'spells': {'descript': 'number of them', 'value': 100}, }, } # 反序列化:字典转模型 SavedWizard = CharacterWizard(**SavedWizard_dict) print(SavedWizard.traits['intelligence'].value) # 输出 20 # 序列化:模型转字典 wizard_dict = SavedWizard.model_dump() print(wizard_dict['traits']['spells']) # 输出 {'descript': 'number of them', 'value': 100}
补充:嵌套BaseModel的替代方案
如果觉得TypedDict不够直观,也可以用嵌套BaseModel的方式实现,序列化/反序列化效果一致:
class BarbarianTraits(BaseModel): strength: Trait[NonNegativeInt] = Trait[NonNegativeInt](descript='the force', value=18) height: Trait[NonNegativeFloat] = Trait[NonNegativeFloat](descript='tallness', value=1.8) weight: Trait[NonNegativeFloat] = Trait[NonNegativeFloat](descript='width', value=92.1) class CharacterBarbarian(BaseModel): id: int name: str = 'Barbarok' traits: BarbarianTraits = BarbarianTraits()
原写法的问题说明
你最初直接在类中写traits = {...}的方式,会被Pydantic识别为类属性而非模型字段,因此不会参与序列化/反序列化,也不会进行类型校验。必须通过定义字段类型(如TypedDict或嵌套BaseModel),让Pydantic将其识别为模型的一部分。
内容的提问来源于stack exchange,提问作者Nordico
相关产品推荐
相关产品推荐

