如何在Pydantic验证器中比较字段的新旧值?
如何在Pydantic验证器中比较字段的新旧值?
我尝试在Pydantic验证器中比较字段的新旧值,但当前实现无法获取旧值,代码如下:
from pydantic import BaseModel, validator class Foo(BaseModel): a: int b: int c: int class Config: validate_assignment = True @validator("b", always=True) def validate_b(cls, v, values, field): # field 不包含当前值 # values 包含其他字段的值,但不包含'b'的旧值 if values.get("b") == 0: # 基于旧值的假想逻辑 return values.get("b") - 1 return v f = Foo(a=1, b=0, c=2) f.b = 3 assert f.b == -1 # 断言失败
我还试过属性设置器,但在Pydantic中不生效,曾以为这是Bug并提交了相关Issue。
解决方案
在Pydantic v1中,字段级@validator是类方法,无法直接访问实例的旧值。要实现基于旧值的验证逻辑,可采用以下两种方式:
1. 重载__setattr__方法
直接重载模型的__setattr__,在设置属性前获取旧值,执行自定义逻辑后再调用父类方法:
from pydantic import BaseModel class Foo(BaseModel): a: int b: int c: int class Config: validate_assignment = True def __setattr__(self, name, value): if name == "b": old_value = object.__getattribute__(self, name) if old_value == 0: value = old_value - 1 super().__setattr__(name, value) f = Foo(a=1, b=0, c=2) f.b = 3 assert f.b == -1 # 断言成功
2. 使用root_validator实现赋值验证
结合Pydantic验证流程,用root_validator并设置skip_on_failure=False,通过self访问实例旧值:
from pydantic import BaseModel, root_validator class Foo(BaseModel): a: int b: int c: int class Config: validate_assignment = True @root_validator(skip_on_failure=False) def validate_b(cls, values, self): if "b" in values: old_value = self.b if hasattr(self, "b") else None if old_value == 0: values["b"] = old_value - 1 return values f = Foo(a=1, b=0, c=2) f.b = 3 assert f.b == -1 # 断言成功
说明
字段级@validator在赋值验证时,values仅包含其他字段的当前值,不包含当前字段的旧值,这是Pydantic v1的设计逻辑,并非Bug。若使用Pydantic v2,推荐用model_validator并指定mode参数,能更便捷地访问实例与旧值。
内容的提问来源于stack exchange,提问作者aiven
相关产品推荐
相关产品推荐

