You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 23:15:50