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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:41:02