如何在Pydantic中根据age字段条件设置school字段为可选?
解决Pydantic Student模型中school字段的条件可选问题
需求回顾
需要实现一个Student模型:
- 当
age字段值小于6时,school字段可选 - 当
age字段值大于等于6时,school字段为必填项
原模型代码:
from pydantic import BaseModel class Student(BaseModel): name: str age: int school: str # 正常情况验证通过 student = Student(**{ "name": "Tom", "age": 10, "school": "Blabla"}) # 期望通过但实际报错 baby_student = Student(**{ "name": "Tom", "age": 5})
你之前尝试的问题分析
尝试代码1的问题:
直接给values["school"] = None,但原模型中school被定义为str类型,不允许None值,因此触发ValidationError。尝试代码2的问题:
在root_validator中动态修改类的__annotations__是无效的——Pydantic在类定义阶段就已经完成了字段规则的解析,运行时修改不会生效,而且这种全局修改会破坏其他场景下的校验逻辑。
正确解决方案
方法1:Pydantic v2 写法(推荐)
先将school定义为Optional[str]并设置默认值None,再通过model_validator添加条件校验:
from pydantic import BaseModel, model_validator, ValidationError from typing import Optional class Student(BaseModel): name: str age: int school: Optional[str] = None @model_validator(mode='after') def check_school_required(self): # 当年龄>=6时,school必须不为空 if self.age >= 6 and self.school is None: raise ValueError("school is required when age is 6 or older") return self # 测试用例 student = Student(**{"name": "Tom", "age": 10, "school": "Blabla"}) # 验证通过 baby_student = Student(**{"name": "Tom", "age": 5}) # 验证通过 # 校验失败场景 try: invalid_student = Student(**{"name": "Alice", "age": 7}) except ValidationError as e: print(e)
方法2:Pydantic v1 写法
如果仍在使用Pydantic v1,可使用root_validator实现相同逻辑:
from pydantic import BaseModel, root_validator, ValidationError from typing import Optional class Student(BaseModel): name: str age: int school: Optional[str] = None @root_validator(skip_on_failure=True) def check_school_required(cls, values): age = values.get("age") school = values.get("school") if age >= 6 and school is None: raise ValueError("school is required when age is 6 or older") return values # 测试用例同上
核心思路
先放宽school的字段类型允许None,再通过验证器补充条件必填的规则,既满足低龄学生无需填写school的需求,又保证高龄学生的school字段必须存在。
内容的提问来源于stack exchange,提问作者soapcmd
相关产品推荐
相关产品推荐

