Pydantic泛型模型嵌套枚举:指定枚举值校验写法无效问题
问题描述
在使用Pydantic解析嵌套泛型模型中的枚举类型时,无法实现仅允许特定枚举值通过校验的需求。当前代码中,typer: OuterContainer[EnumContainer[MyEnum.B]]的写法并未生效,传入'a'依然能通过校验,期望仅当枚举值为MyEnum.B(即'b')时才允许通过。
原代码如下:
from enum import Enum from pydantic import BaseModel, GenericModel from typing import TypeVar, Generic class MyEnum(str, Enum): A = 'a', B = 'b', C = 'c' enumT = TypeVar('enumT',bound=MyEnum) class EnumContainer(GenericModel,Generic[enumT]): enum_value: enumT containerT = TypeVar('containerT', bound=EnumContainer) class OuterContainer(GenericModel,Generic[containerT]): container: containerT class testEnumparsing(BaseModel): typer: OuterContainer[EnumContainer[MyEnum.B]] class Config: orm_mode = True obj = testEnumparsing( typer= OuterContainer( container=EnumContainer(enum_value='a') ) ) parsed = testEnumparsing.from_orm(obj) print(parsed)
解决方案
问题核心是MyEnum.B是枚举实例,而泛型参数要求传入类型,所以原写法无法起到值限定作用。以下两种方式可解决该问题:
方式一:用Literal限定枚举值
通过typing.Literal直接指定允许的枚举实例,精准限定合法值:
from enum import Enum from pydantic import BaseModel, GenericModel from typing import TypeVar, Generic, Literal class MyEnum(str, Enum): A = 'a' B = 'b' C = 'c' enumT = TypeVar('enumT', bound=MyEnum) class EnumContainer(GenericModel, Generic[enumT]): enum_value: enumT containerT = TypeVar('containerT', bound=EnumContainer) class OuterContainer(GenericModel, Generic[containerT]): container: containerT class testEnumparsing(BaseModel): # 限定EnumContainer的enum_value必须为MyEnum.B typer: OuterContainer[EnumContainer[Literal[MyEnum.B]]] class Config: orm_mode = True # 错误测试:传入'a'会触发校验失败 try: obj = testEnumparsing( typer=OuterContainer( container=EnumContainer(enum_value='a') ) ) parsed = testEnumparsing.from_orm(obj) print(parsed) except Exception as e: print(f"校验失败:{e}") # 正确示例:传入'b'正常通过 obj_valid = testEnumparsing( typer=OuterContainer( container=EnumContainer(enum_value='b') ) ) parsed_valid = testEnumparsing.from_orm(obj_valid) print(parsed_valid)
方式二:自定义字段校验器
在testEnumparsing类中添加校验逻辑,直接检查嵌套的枚举值:
from enum import Enum from pydantic import BaseModel, GenericModel, validator from typing import TypeVar, Generic class MyEnum(str, Enum): A = 'a' B = 'b' C = 'c' enumT = TypeVar('enumT', bound=MyEnum) class EnumContainer(GenericModel, Generic[enumT]): enum_value: enumT containerT = TypeVar('containerT', bound=EnumContainer) class OuterContainer(GenericModel, Generic[containerT]): container: containerT class testEnumparsing(BaseModel): typer: OuterContainer[EnumContainer[MyEnum]] class Config: orm_mode = True @validator('typer') def check_enum_value(cls, v): if v.container.enum_value != MyEnum.B: raise ValueError(f"枚举值必须为{MyEnum.B}") return v # 错误测试:传入'a'触发校验失败 try: obj = testEnumparsing( typer=OuterContainer( container=EnumContainer(enum_value='a') ) ) parsed = testEnumparsing.from_orm(obj) print(parsed) except Exception as e: print(f"校验失败:{e}") # 正确示例:传入'b'正常通过 obj_valid = testEnumparsing( typer=OuterContainer( container=EnumContainer(enum_value='b') ) ) parsed_valid = testEnumparsing.from_orm(obj_valid) print(parsed_valid)
关键注意点
- 原代码中
MyEnum的枚举值后多了逗号,会导致枚举值变成元组(如MyEnum.A的值为('a',)而非'a'),需去掉逗号避免解析异常。 - 泛型参数仅接受类型,
Literal是实现"限定具体枚举实例"需求的标准方式。
内容的提问来源于stack exchange,提问作者alosbh
相关产品推荐
相关产品推荐

