如何使用Pydantic与FastAPI正确验证递归结构的Filter模型数据?
解决Pydantic递归Union模型的类型识别问题
你的问题出在两个关键点上:一是type没有被定义为Pydantic的字段,二是没有利用Pydantic的鉴别器功能来明确区分不同的过滤器模型。下面是具体的解决方法:
1. 修正模型定义(核心修改)
首先,把SimpleFilter和CompoundFilter里的type从类属性改为Pydantic字段,然后给subfilters字段添加鉴别器,让Pydantic能根据type字段的值自动选择对应的模型验证:
from enum import Enum from typing import Any, List, Union from pydantic import BaseModel, Field class FilterType(str, Enum): SIMPLE = "simple" COMPOUND = "compound" class Operator(str, Enum): AND = "and" OR = "or" class FilterAction(str, Enum): INCLUDE = "include" EXCLUDE = "exclude" class Comparator(str, Enum): EQUAL = "==" NOT_EQUAL = "!=" # 注意:你的测试数据用了">=",需要补充这个枚举值,否则会验证失败 GREATER_THAN_OR_EQUAL = ">=" class SimpleFilter(BaseModel): # 将type改为Pydantic字段,设置默认值 type: FilterType = FilterType.SIMPLE action: FilterAction = FilterAction.EXCLUDE comparator: Comparator criterion: Any class CompoundFilter(BaseModel): # 同样将type改为Pydantic字段 type: FilterType = FilterType.COMPOUND operator: Operator = Operator.AND # 为subfilters添加discriminator,指定根据type字段区分模型 subfilters: List[Union[SimpleFilter, "CompoundFilter"]] = Field( default_factory=list, discriminator="type" ) CompoundFilter.update_forward_refs()
2. 关键修改说明
- 将
type改为Pydantic字段:原来的type = FilterType.SIMPLE是类属性,Pydantic不会把它作为模型的一部分进行验证和解析。改成type: FilterType = FilterType.SIMPLE后,这个字段会被纳入验证逻辑,传入的JSON中的type值会被正确读取。 - 添加鉴别器
discriminator="type":这个参数告诉Pydantic,对于Union[SimpleFilter, CompoundFilter]类型的元素,要根据它们的type字段值来选择对应的模型。当type为"simple"时用SimpleFilter验证,为"compound"时用CompoundFilter验证,彻底避免了顺序匹配导致的错误。
3. 测试修正后的代码
注意你的测试数据里有两个小问题:SimpleFilter要求必填criterion字段,且comparator: ">="不在原来的枚举里,修正后的数据如下:
data = { "type": "compound", "operator": "and", "subfilters": [ { "type": "simple", "action": "exclude", "comparator": ">=", "criterion": 100 # 补充必填的criterion字段 } ] } # 实例化验证 filter_obj = CompoundFilter(**data) print(filter_obj.subfilters[0]) # 输出:type=<FilterType.SIMPLE: 'simple'> action=<FilterAction.EXCLUDE: 'exclude'> comparator=<Comparator.GREATER_THAN_OR_EQUAL: '>='> criterion=100
现在subfilters里的元素会被正确识别为SimpleFilter类型,而不是错误匹配到CompoundFilter。
内容的提问来源于stack exchange,提问作者Jahongir Rahmonov
相关产品推荐
相关产品推荐

