Pydantic模型字段间依赖的校验方案求解
解决Pydantic模型字段依赖校验的方案
方法1:根校验器(Root Validator)
用根校验器可以直接访问整个模型的字段值,集中处理版本与字段的依赖逻辑,完全符合单一父类的需求:
from pydantic import BaseModel, root_validator, ValidationError # 从数据库获取的选项 options_v1 = ("a", "b", "c") options_v2 = ("d", "e", "f") class Model(BaseModel): version: int field: str @root_validator(skip_on_failure=True) def check_field_version_match(cls, values): version = values.get("version") field = values.get("field") if version == 1 and field not in options_v1: raise ValueError(f"version=1时,field必须是{options_v1}中的一个") elif version == 2 and field not in options_v2: raise ValueError(f"version=2时,field必须是{options_v2}中的一个") # 可按需扩展更多版本的校验规则 return values # 测试示例 try: valid_v1 = Model(version=1, field="a") print(valid_v1) valid_v2 = Model(version=2, field="d") print(valid_v2) invalid = Model(version=1, field="d") except ValidationError as e: print(e)
skip_on_failure=True的作用是:如果version字段本身校验失败(比如传入非整数),会跳过这个校验器,避免无意义的报错。
方法2:字段校验器(Field Validator)
如果只需要针对field字段做校验,可以用字段校验器结合values参数获取版本值:
from pydantic import BaseModel, field_validator, ValidationError options_v1 = ("a", "b", "c") options_v2 = ("d", "e", "f") class Model(BaseModel): version: int field: str @field_validator("field") def validate_field_by_version(cls, value, values): # Pydantic v2用values.data获取已校验字段,v1直接用values version = values.data.get("version") if version == 1 and value not in options_v1: raise ValueError(f"version=1时,field只能是{options_v1}中的值") elif version == 2 and value not in options_v2: raise ValueError(f"version=2时,field只能是{options_v2}中的值") return value
方法3:保留类型提示的动态校验
如果希望IDE能给出字段的类型提示(比如提示可选值),可以结合Literal和校验器实现:
from pydantic import BaseModel, ValidationError, root_validator from typing import Literal, Union options_v1 = ("a", "b", "c") options_v2 = ("d", "e", "f") FieldV1 = Literal[options_v1] FieldV2 = Literal[options_v2] class Model(BaseModel): version: int field: Union[FieldV1, FieldV2] @root_validator(skip_on_failure=True) def match_version_field(cls, values): version, field = values.get("version"), values.get("field") if version == 1 and field not in options_v1: raise ValueError(f"version=1时,field必须是{options_v1}中的一个") elif version == 2 and field not in options_v2: raise ValueError(f"version=2时,field必须是{options_v2}中的一个") return values
这种方式既保留了类型提示的优势,又实现了版本依赖的校验逻辑。
选型建议
优先用方法1,逻辑集中清晰,易于扩展,完全适配单一父类的需求;如果只关注field字段的校验,方法2更简洁;看重类型提示的话可以选方法3。
内容的提问来源于stack exchange,提问作者dino
相关产品推荐
相关产品推荐

