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

如何用Pydantic建模含限定键的嵌套JSON并保留对象行为?

解决方案

步骤1:定义区域映射模型(RegionMap)

创建RegionMap模型,将us和mx设为可选的Region类型,既限制了允许的键值,又支持JSON仅包含单个区域的场景,同时保留对象的点访问行为。

步骤2:添加直接访问person的快捷属性

在RegionMap中通过@property实现person的快捷访问逻辑,当仅存在一个区域时,直接返回该区域的person实例。

步骤3:添加区域存在性验证

使用Pydantic根验证器,确保RegionMap至少包含us或mx中的一个,避免空区域的非法情况。

完整代码实现

from pydantic import BaseModel, root_validator, ValidationError
from typing import Optional

class Person(BaseModel):
    name: str

class Region(BaseModel):
    person: Person

class RegionMap(BaseModel):
    us: Optional[Region] = None
    mx: Optional[Region] = None

    @root_validator(pre=False)
    def check_at_least_one_region(cls, values):
        us, mx = values.get('us'), values.get('mx')
        if us is None and mx is None:
            raise ValueError("Region must contain at least 'us' or 'mx'")
        return values

    @property
    def person(self) -> Person:
        regions = [r for r in [self.us, self.mx] if r is not None]
        if len(regions) != 1:
            raise ValueError("Cannot access 'person' directly: region has multiple or no entries")
        return regions[0].person

class Company(BaseModel):
    name: str
    region: RegionMap

使用示例

解析单个区域的JSON

json_data_single = {
    'name': 'My Company',
    'region': {
        'mx': {
            'person': {
                'name': 'Juan'
            }
        }
    }
}

company = Company(**json_data_single)
print(company.region.mx.person.name)  # 输出: Juan
print(company.region.person.name)     # 输出: Juan

解析双区域的JSON

json_data_both = {
    'name': 'My Company',
    'region': {
        'us': {
            'person': {
                'name': 'John'
            }
        },
        'mx': {
            'person': {
                'name': 'Juan'
            }
        }
    }
}

company = Company(**json_data_both)
print(company.region.us.person.name)  # 输出: John
print(company.region.mx.person.name)  # 输出: Juan
# 多区域时直接访问person会触发报错
try:
    print(company.region.person.name)
except ValueError as e:
    print(e)  # 输出: Cannot access 'person' directly: region has multiple or no entries

拦截非法键的情况

json_data_invalid = {
    'name': 'My Company',
    'region': {
        'ca': {
            'person': {
                'name': 'Alice'
            }
        }
    }
}

try:
    Company(**json_data_invalid)
except ValidationError as e:
    print(e)  # 提示额外字段'ca'不被允许

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 23:47:25