Pydantic V2 - @field_validator `values` 参数等效

Dan*_*ong 9 python pydantic

我正在从 Pydantic v1 迁移到 v2,并尝试用 @field_validator 替换已弃用的 @validator 的所有使用。

以前,我使用values验证器函数的参数来引用其他先前验证的字段的值。正如v1 文档所说

您还可以将以下参数的任意子集添加到签名中(名称必须匹配):

  • 值:包含任何先前验证的字段的名称到值映射的字典

由于签名已更改,此参数似乎values不再被传递。但是,迁移文档没有提及v2 中的等效项,并且 v2 验证器文档页面尚未针对 v2.0 进行更新。@field_validatorvalues

有谁知道 v2 的首选方法?

V1验证器:

@validator('password2')
def passwords_match(cls, v, values, **kwargs):
    if 'password1' in values and v != values['password1']:
        raise ValueError('passwords do not match')
    return v
Run Code Online (Sandbox Code Playgroud)

Dan*_*erg 8

当前版本的 Pydantic v2 文档实际上对于字段验证器部分来说是最新的,就验证方法的签名必须/可以是什么样子而言。

  • 第二个参数是要验证的字段值;可以随意命名
  • 第三个参数是一个实例pydantic.ValidationInfo

[...]

如果您想访问 中另一个字段的值@field_validator,可以使用ValidationInfo.data,它是字段名称到字段值的字典。验证是按照定义字段的顺序完成的,因此在使用时必须小心,ValidationInfo.data不要访问尚未验证/填充的字段 [...]

ValidationData(旁注:您可以在Pydantic Core API 参考中查找有关该协议的更多信息,尽管它有点简洁并且可以进行一些交叉引用。)


假设您在 Pydantic v1 中有以下代码:

from typing import Any

from pydantic import BaseModel, ValidationError, validator


class UserModel(BaseModel):
    ...
    password1: str
    password2: str

    @validator("password2")
    def passwords_match(cls, v: str, values: dict[str, Any]) -> str:
        if "password1" in values and v != values["password1"]:
            raise ValueError("passwords do not match")
        return v


try:
    UserModel(password1="abc", password2="xyz")
except ValidationError as err:
    print(err.json(indent=4))
Run Code Online (Sandbox Code Playgroud)

输出:

[
    {
        "loc": [
            "password2"
        ],
        "msg": "passwords do not match",
        "type": "value_error"
    }
]
Run Code Online (Sandbox Code Playgroud)

你必须在 v2 中像这样重写它:

from pydantic import BaseModel, ValidationError, ValidationInfo, field_validator


class UserModel(BaseModel):
    ...
    password1: str
    password2: str

    @field_validator("password2")
    def passwords_match(cls, v: str, info: ValidationInfo) -> str:
        if "password1" in info.data and v != info.data["password1"]:
            raise ValueError("passwords do not match")
        return v


try:
    UserModel(password1="abc", password2="xyz")
except ValidationError as err:
    print(err.json(indent=4))
Run Code Online (Sandbox Code Playgroud)

v2输出:

[
    {
        "type": "value_error",
        "loc": [
            "password2"
        ],
        "msg": "Value error, passwords do not match",
        "input": "xyz",
        "ctx": {
            "error": "passwords do not match"
        },
        "url": "https://errors.pydantic.dev/2.6/v/value_error"
    }
]
Run Code Online (Sandbox Code Playgroud)