如何用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
相关产品推荐
相关产品推荐

