如何基于外部API返回的动态选项创建Pydantic枚举字段
实现方案
该需求完全可以实现。Literal属于静态类型声明,必须在代码定义阶段写死所有可选值,无法直接传入运行时从外部API获取的动态选项,以下是两种可直接落地的实现方式:
方案一:运行时动态生成枚举类
Python原生Enum支持运行时动态创建,你可以先请求外部API拿到所有合法的音频语言取值,再基于返回结果动态生成LanguageAudioEnum,后续模型定义和你原有写法完全兼容。
示例代码:
from enum import Enum from typing import Optional from pydantic import BaseModel, root_validator # 替换为真实的外部API调用逻辑,获取所有合法的音频语言选项 def fetch_valid_audio_langs() -> list[str]: # 模拟接口返回 return ["pear", "banana", "orange", "grape"] valid_audio_options = fetch_valid_audio_langs() # 动态生成枚举类 LanguageAudioEnum = str(Enum( value="LanguageAudioEnum", names={opt: opt for opt in valid_audio_options} )) class Language(BaseModel): language_audio: Optional[LanguageAudioEnum] = None language_booklet: Optional[str] = None language_live: Optional[str] = None @root_validator(pre=True) @classmethod def check_only_one_language_selected(cls, values): # 修正原逻辑的问题:过滤值为None的默认字段,避免长度统计错误 filled_fields = [k for k, v in values.items() if v is not None] if len(filled_fields) > 1: raise ValueError("Select only one language option") elif len(filled_fields) == 0: raise ValueError("Select language option") return values
方案二:通过字段校验器做动态值校验
如果不需要枚举类型的特性,也可以直接给language_audio字段加单独的校验器,在校验逻辑中匹配从API拉取的合法值列表,这种方式更灵活,适合接口返回的可选值会不定期更新的场景。
示例代码:
from typing import Optional from pydantic import BaseModel, root_validator, validator # 替换为真实的外部API调用逻辑 valid_audio_options = ["pear", "banana", "orange", "grape"] class Language(BaseModel): language_audio: Optional[str] = None language_booklet: Optional[str] = None language_live: Optional[str] = None @validator("language_audio") def validate_audio_lang(cls, v): if v is None: return v if v not in valid_audio_options: raise ValueError(f"Invalid audio language, allowed values: {', '.join(valid_audio_options)}") return v @root_validator(pre=True) @classmethod def check_only_one_language_selected(cls, values): filled_fields = [k for k, v in values.items() if v is not None] if len(filled_fields) > 1: raise ValueError("Select only one language option") elif len(filled_fields) == 0: raise ValueError("Select language option") return values
注意:你原代码中的根校验器存在逻辑漏洞:未传值的字段如果默认是None,也会被计入
values字典的键,导致“仅选一个语言”的校验误判,上述两个示例都已经修正了这个问题。
内容的提问来源于stack exchange,提问作者Oz Cohen
相关产品推荐
相关产品推荐

