Validators

四种validator

Pydantic提供了四种validator

  • BeforeValidator
    运行在Pydantic内部的校验转换之前,入参为输入值Any,返回值为Any。
  • AfterValidator
    运行在Pydantic内部的校验转换之后,入参和返回值为正确的字段类型。
  • PlainValidator
    运行时间和BeforeValidator相同,但执行完之后整个校验过程结束,不再执行其他validator和Pydantic内部的校验流程。
  • WrapValidator
    可以运行在pydantic和其他validator之前或者之后,或者返回值、抛出异常立即结束校验流程。

可以使用多个BeforeValidator、AfterValidator和WrapperValidator,但是只能有一个PlainValidator。

关于执行顺序,从右到左执行所有Before和Wrap校验器,再从左到右执行所有After校验器。

以下示例展示了validator的用法。

from typing import Any, List

from pydantic import BaseModel, ValidationError
from pydantic.functional_validators import AfterValidator, BeforeValidator, WrapValidator
from pydantic_core.core_schema import ValidatorFunctionWrapHandler, ValidationInfo
from typing_extensions import Annotated


def check_squares(v: int) -> int:
    print('square')
    assert v ** 0.5 % 1 == 0, f'{v} is not a square number'
    return v


def double(v: Any) -> Any:
    print('double')
    return v * 2


def maybe_strip_whitespace(
        v: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
) -> int:
    print('wrap')
    if not isinstance(v, int):
        v = int(v)
    if v >= 22:
        try:
            # 执行后续校验器链
            return handler(v)
        except ValidationError as e:
            print(e)
            return handler(v / 2)
    # 直接返回,结束校验
    return v


MyNumber = Annotated[int, AfterValidator(check_squares), WrapValidator(maybe_strip_whitespace), BeforeValidator(double)]


class DemoModel(BaseModel):
    number: List[MyNumber]

print(DemoModel(number=[8, '2']))
'''
double
wrap
double
wrap
square
1 validation error for ValidatorCallable
  Assertion failed, 22 is not a square number [type=assertion_error, input_value=22, input_type=int]
    For further information visit https://errors.pydantic.dev/2.1/v/assertion_error
square
1 validation error for DemoModel
number.1
  Assertion failed, 11 is not a square number [type=assertion_error, input_value=11.0, input_type=float]
    For further information visit https://errors.pydantic.dev/2.1/v/assertion_error
'''

@field_validator

  • field_validator可以是Before或者AfterValidator(默认)。
  • field_validator装饰的方法为类方法,第一个参数是当前Model类。
  • 第二个可变参数是要校验的字段名,可以是多个,'*'表示所有字段。
  • 如果有第三个参数,则是pydantic.FieldValidationInfo,校验信息。
  • check_fields关键字参数,检验字段是否存在在对象身上。
  • 要么抛出ValidationError和AssertionError,要么返回处理过的值。

字段校验按照定义的顺序进行,所以在使用ValidationInfo时需要注意访问的字段是否已经被校验处理过,如果要使用多个字段信息进行验证,可以使用@model_validator。

@model_validator

  • model_validator可以是mode=‘before’, mode=‘after’ or mode=‘wrap’。
  • mode=‘before’,装饰的方法是一个类方法,第一个参数是cls类,第二个参数是Dict[str, Any],即原始输入(如果没有被model='wrap’修改的话),第三个参数(如果有)是ValidationInfo,返回值是Dict[str, Any]。
  • mode=‘after’,在validator和pydantic校验完成之后调用,是实例方法,只有一个参数self,此时属性已在实例对象上。
  • mode=‘wrap’,类方法,在before之前被调用,第一个参数是cls,第二个参数是原始输入Dict[str, Any],第三个参数是ValidatorCallable校验器链,接受一个参数执行后续校验流程,第四个参数是ValidationInfo。

Special Types

  • SkipValidation,跳过验证
  • InstanceOf,相当于isincetance(obj, cls)
class Model(BaseModel):
    names: List[SkipValidation[str]]
    values: List[instanceOf[int]]

Validation Context

运行时动态修改校验行为,文档

Q.E.D.


一切很好,不缺烦恼。