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

如何用Pydantic实现对象列表与键值字典的双向序列化?

实现方法

要实现列表与键为子对象属性的字典之间的双向序列化/反序列化,可通过自定义Pydantic字段处理器完成,具体步骤如下:

1. 编写双向转换逻辑

先实现两个核心函数,分别处理列表转字典(序列化)、字典转列表(反序列化)的逻辑:

import uuid
from typing import List, Dict, Any
from pydantic import BaseModel

# 序列化:把Recipe列表转为以id为键的字典,同时剔除Recipe对象里的id字段
def serialize_recipes(recipes: List["Recipe"]) -> Dict[str, Dict[str, Any]]:
    return {str(recipe.id): recipe.model_dump(exclude={"id"}) for recipe in recipes}

# 反序列化:把字典转回Recipe列表,字典的键作为Recipe的id
def deserialize_recipes(recipes_dict: Dict[str, Dict[str, Any]]) -> List["Recipe"]:
    return [Recipe(id=uuid.UUID(recipe_id), **recipe_data) for recipe_id, recipe_data in recipes_dict.items()]

2. 自定义Pydantic字段类型

使用Annotated结合Pydantic的序列化/反序列化处理器,创建可复用的字段类型:

from typing import Annotated
from pydantic import BeforeValidator, PlainSerializer, WithJsonSchema
from pydantic_core import core_schema

RecipeDict = Annotated[
    List[Recipe],
    # 反序列化时触发:字典转列表
    BeforeValidator(deserialize_recipes),
    # 序列化时触发:列表转字典
    PlainSerializer(serialize_recipes, return_type=dict),
    # 指定序列化后的JSON Schema格式
    WithJsonSchema(
        {
            "type": "object",
            "additionalProperties": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "description": {"type": "string"}
                },
                "required": ["name", "description"]
            }
        },
        mode="serialization",
    ),
    # 指定反序列化时的JSON Schema格式
    WithJsonSchema(
        {
            "type": "array",
            "items": core_schema.json_schema(Recipe.model_json_schema())
        },
        mode="deserialization",
    ),
]

3. 修改模型类

将CountryDetails中的recipes字段替换为自定义的RecipeDict类型:

class Recipe(BaseModel):
    id: uuid.UUID
    name: str
    description: str

class CountryDetails(BaseModel):
    name: str
    recipes: RecipeDict

4. 测试验证

以下代码可验证序列化和反序列化是否正常工作:

# 测试序列化:生成目标JSON格式
recipe1 = Recipe(id=uuid.UUID("a1acd620-0e87-4cbe-8d15-a4a3aff00cc3"), name="shrimp on the barbie", description="classic prawn on the BBQ")
recipe2 = Recipe(id=uuid.UUID("175f2a58-33c4-4886-920f-cb073101f104"), name="vegemite toast", description="toast + vegemite; nice")
country = CountryDetails(name="australia", recipes=[recipe1, recipe2])
print(country.model_dump_json(indent=2))

# 测试反序列化:从目标JSON转回对象
json_str = '''
{
  "name": "australia",
  "recipes": {
    "a1acd620-0e87-4cbe-8d15-a4a3aff00cc3": {
      "name": "shrimp on the barbie",
      "description": "classic prawn on the BBQ"
    },
    "175f2a58-33c4-4886-920f-cb073101f104": {
      "name": "vegemite toast",
      "description": "toast + vegemite; nice"
    }
  }
}
'''
deserialized_country = CountryDetails.model_validate_json(json_str)
print(deserialized_country.recipes)

关键说明

  • 序列化时通过PlainSerializer自动调用转换函数,把列表转为指定格式的字典,同时剔除重复的id字段;
  • 反序列化时通过BeforeValidator触发反向转换,从字典重构出对象列表;
  • 配置WithJsonSchema确保生成的JSON Schema符合预期,适配前后端交互的格式要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:02:34