如何在Pydantic模型中用@validator校验日期先后顺序?
问题分析与解决方案
你的代码存在几个关键问题导致校验不生效:
- 校验顺序错误:
startFrom在StartTo之前定义,Pydantic默认按字段定义顺序执行校验,校验startFrom时StartTo还未完成解析,因此values中没有StartTo,直接跳过了核心校验逻辑。 - Optional字段配置矛盾:你给
Optional字段设置了...(必填标记),这会让字段变成必填,和Optional的定义冲突,正确的默认值应该是None。 - 未处理
StartTo为None的情况:即使StartTo存在于values中,若值为None,直接比较startFrom > None会引发错误,且这种场景无需校验。
修正方案(分Pydantic版本)
方案1:Pydantic v1 使用root_validator
root_validator会在所有字段解析完成后执行,能确保拿到两个字段的最终值:
from pydantic import BaseModel, Field, root_validator from typing import Optional from datetime import date class MyModel(BaseModel): startFrom: Optional[date] = Field( None, # Optional字段默认值设为None description='XXX', example='2023-03-15', ) StartTo: Optional[date] = Field( None, description='XXX', example='2023-03-31', ) otherData: str = Field( ..., description='XXX', example='XX', ) @root_validator(skip_on_failure=True) def check_date_order(cls, values): start_from = values.get('startFrom') start_to = values.get('StartTo') # 仅当两个字段都不为空时执行校验 if start_from is not None and start_to is not None: if start_from > start_to: raise ValueError('startFrom must be earlier than StartTo') return values
方案2:Pydantic v2 使用model_validator
v2中root_validator被弃用,改用model_validator:
from pydantic import BaseModel, Field, model_validator from typing import Optional from datetime import date class MyModel(BaseModel): startFrom: Optional[date] = Field( None, description='XXX', example='2023-03-15', ) StartTo: Optional[date] = Field( None, description='XXX', example='2023-03-31', ) otherData: str = Field( ..., description='XXX', example='XX', ) @model_validator(mode='after') def check_date_order(self): if self.startFrom is not None and self.StartTo is not None: if self.startFrom > self.StartTo: raise ValueError('startFrom must be earlier than StartTo') return self
额外说明
- 若使用FastAPI等框架,当Pydantic抛出
ValidationError时,框架会自动返回422状态码,无需额外处理。 - 建议统一字段命名风格(比如把
StartTo改为startTo),避免大小写混淆引发的隐性问题。
内容的提问来源于stack exchange,提问作者Da sil
相关产品推荐
相关产品推荐

