如何设置关联主类别列表的带值限制嵌套Pydantic模型?
实现关联限制的嵌套Pydantic模型
首先修正你给出的枚举类定义错误,正确的枚举需明确每个成员的取值,建议按主类别拆分不同的子类别枚举:
from enum import Enum from pydantic import BaseModel, field_validator, ValidationError, Discriminator, Union, Annotated, Literal # 主类别枚举 class Category(str, Enum): MEAT = "Meat" VEGETABLE = "Vegetable" GRAIN = "Grain" # 按主类别拆分的子类别枚举 class MeatSubCategory(str, Enum): BEEF = "Beef" POULTRY = "Poultry" SEAFOOD = "Seafood" class VegetableSubCategory(str, Enum): GREEN_VEG = "GreenVegetable" ROOT_VEG = "RootVegetable" class GrainSubCategory(str, Enum): WHEAT = "Wheat" RICE = "Rice"
方法一:使用字段验证器(field_validator)
定义包含主类别和子类别的模型,通过验证器关联两者的取值限制:
class ProductCategory(BaseModel): category: Category sub_category: str @field_validator("sub_category") def validate_sub_category(cls, v, values): # 获取当前传入的主类别 category = values.data.get("category") if not category: return v # 映射主类别到允许的子类别列表 category_sub_map = { Category.MEAT: [item.value for item in MeatSubCategory], Category.VEGETABLE: [item.value for item in VegetableSubCategory], Category.GRAIN: [item.value for item in GrainSubCategory] } if v not in category_sub_map[category]: allowed_subs = ", ".join(category_sub_map[category]) raise ValueError(f"当主类别为{category}时,子类别只能是:{allowed_subs}") return v
测试示例:
# 合法数据 valid_data = ProductCategory(category=Category.MEAT, sub_category="Beef") print(valid_data) # 非法数据(主类别是Meat,子类别用了RootVegetable) try: invalid_data = ProductCategory(category=Category.MEAT, sub_category="RootVegetable") except ValidationError as e: print(e)
方法二:使用鉴别联合(Discriminated Union)
这种方式类型提示更清晰,Pydantic会自动根据主类别字段匹配对应的子模型:
# 为每个主类别创建对应子模型 class MeatCategory(BaseModel): category: Literal[Category.MEAT] = Category.MEAT sub_category: MeatSubCategory class VegetableCategory(BaseModel): category: Literal[Category.VEGETABLE] = Category.VEGETABLE sub_category: VegetableSubCategory class GrainCategory(BaseModel): category: Literal[Category.GRAIN] = Category.GRAIN sub_category: GrainSubCategory # 定义鉴别联合模型 ProductCategory = Annotated[ Union[MeatCategory, VegetableCategory, GrainCategory], Discriminator("category") ]
测试示例:
# 合法数据 valid_meat = ProductCategory(category=Category.MEAT, sub_category=MeatSubCategory.BEEF) print(valid_meat) # 非法数据(主类别是Vegetable,子类别用了Beef) try: invalid_data = ProductCategory(category=Category.VEGETABLE, sub_category=MeatSubCategory.BEEF) except ValidationError as e: print(e)
两种方法对比:
- 方法一适合简单场景,修改灵活,无需创建多个子模型
- 方法二更符合类型安全,IDE能提供准确的类型提示,适合复杂的类别体系
内容的提问来源于stack exchange,提问作者Oday Salim
相关产品推荐
相关产品推荐

