如何判断Pydantic模型中Union类型值匹配的具体分支?
判断Pydantic Union类型字段匹配的分支方法
针对你遇到的问题,这里提供三种实用方法来确定Union类型字段匹配的具体分支:
方法一:值匹配+类型特征检查
利用Literal分支的明确字面量,结合其他分支的类型特征直接判断,适合分支逻辑清晰的场景:
from datetime import datetime from typing import Union, Literal, Tuple, List from pydantic import BaseModel, UUID4, ValidationError class ExportDataRequest(BaseModel): customers: Union[Literal["all"], List[UUID4], UUID4, List[int], int] daterange: Union[Tuple[datetime, datetime], int] data = { "customers": "all", 'daterange': ("2024-01-01", "2024-03-01") } try: model = ExportDataRequest(**data) # 判断customers匹配的分支 if model.customers == "all": print("匹配Literal['all']分支") elif isinstance(model.customers, int): print("匹配int分支") elif isinstance(model.customers, UUID4): print("匹配UUID4分支") elif isinstance(model.customers, list): if all(isinstance(item, UUID4) for item in model.customers): print("匹配List[UUID4]分支") elif all(isinstance(item, int) for item in model.customers): print("匹配List[int]分支") # 判断daterange匹配的分支 if isinstance(model.daterange, tuple) and len(model.daterange) == 2 and all(isinstance(d, datetime) for d in model.daterange): print("匹配Tuple[datetime, datetime]分支") elif isinstance(model.daterange, int): print("匹配int分支") except ValidationError as e: print(e.errors())
方法二:解析类型注解+动态验证
通过typing模块解析Union的分支定义,再用Pydantic的TypeAdapter动态验证值是否符合分支,适合复杂Union场景:
from datetime import datetime from typing import Union, Literal, Tuple, List, get_args, get_origin from pydantic import BaseModel, UUID4, ValidationError, TypeAdapter class ExportDataRequest(BaseModel): customers: Union[Literal["all"], List[UUID4], UUID4, List[int], int] daterange: Union[Tuple[datetime, datetime], int] data = { "customers": "all", 'daterange': ("2024-01-01", "2024-03-01") } try: model = ExportDataRequest(**data) # 处理customers字段 customers_union = ExportDataRequest.model_fields["customers"].annotation if get_origin(customers_union) is Union: for branch in get_args(customers_union): try: TypeAdapter(branch).validate_python(model.customers) print(f"customers匹配分支: {branch}") break except ValidationError: continue # 处理daterange字段 daterange_union = ExportDataRequest.model_fields["daterange"].annotation if get_origin(daterange_union) is Union: for branch in get_args(daterange_union): try: TypeAdapter(branch).validate_python(model.daterange) print(f"daterange匹配分支: {branch}") break except ValidationError: continue except ValidationError as e: print(e.errors())
方法三:自定义字段类型封装Literal分支
把Literal["all"]封装成自定义字段类型,让该分支有独立的类型标识,直接通过isinstance判断:
from datetime import datetime from typing import Union, Tuple, List from pydantic import BaseModel, UUID4, ValidationError, GetCoreSchemaHandler from pydantic_core import core_schema # 自定义类型封装Literal["all"] class AllLiteral(str): @classmethod def __get_pydantic_core_schema__(cls, source_type, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: return core_schema.no_info_after_validator_function( cls, core_schema.literal_schema("all") ) class ExportDataRequest(BaseModel): customers: Union[AllLiteral, List[UUID4], UUID4, List[int], int] daterange: Union[Tuple[datetime, datetime], int] data = { "customers": "all", 'daterange': ("2024-01-01", "2024-03-01") } try: model = ExportDataRequest(**data) print(type(model.customers)) # 输出 <class '__main__.AllLiteral'> if isinstance(model.customers, AllLiteral): print("匹配原Literal['all']分支") # 其他分支判断逻辑同方法一 except ValidationError as e: print(e.errors())
内容的提问来源于stack exchange,提问作者user19954134
相关产品推荐
相关产品推荐

