如何在Pydantic 1.x中兼容驼峰/大驼峰格式数据验证(不可改基类)
如何在不修改Pydantic v1基类的前提下兼容camelCase与PascalCase格式数据验证
问题背景
现有待验证的数据对象:
{'d': {'results': [ {'superHeroPublicId': '1', 'power': '100.00', 'infoText': 'irrelevant'}, {'SuperHeroPublicId': '2', 'Power': '1541.60', 'InfoText': 'irrelevant'} ]}}
以及无法修改的Pydantic v1基类:
class ApiPublicBaseModel(BaseModel): class Config: alias_generator = camelize allow_population_by_field_name = True extra = Extra.ignore json_encoders = { datetime: lambda value: value.isoformat(), }
需求:创建验证模型,同时兼容数据中的camelCase(小驼峰)和PascalCase(大驼峰)格式字段,避免验证失败。
解决方案
方法一:前置根验证器统一转换键名
在子类中添加前置根验证器,遍历输入数据的所有键,将PascalCase格式的键转换为camelCase,适配基类的别名规则。如果有嵌套结构,需要递归处理:
from pydantic import root_validator from typing import Any, Dict from pydantic.base import camelize class SuperHero(ApiPublicBaseModel): super_hero_public_id: str power: str info_text: str @root_validator(pre=True) def normalize_case_keys(cls, values: Dict[str, Any]) -> Dict[str, Any]: def normalize_nested(d: Dict[str, Any]) -> Dict[str, Any]: normalized = {} for key, val in d.items(): # 递归处理嵌套字典 if isinstance(val, dict): val = normalize_nested(val) # 大驼峰转小驼峰:首字母小写 if key and key[0].isupper(): camel_key = key[0].lower() + key[1:] normalized[camel_key] = val else: normalized[key] = val return normalized return normalize_nested(values) # 验证测试 data = {'d': {'results': [ {'superHeroPublicId': '1', 'power': '100.00', 'infoText': 'irrelevant'}, {'SuperHeroPublicId': '2', 'Power': '1541.60', 'InfoText': 'irrelevant'} ]}} for hero_item in data['d']['results']: hero = SuperHero(**hero_item) print(hero.dict(by_alias=True)) # 输出camelCase格式的结果
方法二:为字段手动映射多格式键
如果不想全局转换,可以为每个字段单独处理PascalCase的键,利用root_validator将大驼峰键的值赋值给对应字段:
class SuperHero(ApiPublicBaseModel): super_hero_public_id: str power: str info_text: str @root_validator(pre=True) def map_pascal_case_keys(cls, values: Dict[str, Any]) -> Dict[str, Any]: # 逐个映射大驼峰键到小驼峰键 if 'SuperHeroPublicId' in values: values['superHeroPublicId'] = values.pop('SuperHeroPublicId') if 'Power' in values: values['power'] = values.pop('Power') if 'InfoText' in values: values['infoText'] = values.pop('InfoText') return values
这种方式适合字段较少的场景,缺点是需要手动维护所有可能的大驼峰键映射。
内容的提问来源于stack exchange,提问作者error404
相关产品推荐
相关产品推荐

