Pydantic 字段验证装饰器field_validator教程

引言

在构建数据驱动的应用程序时,确保输入数据的准确性和完整性至关重要。Pydantic 是一个 Python 库,它提供了一种简单而强大的方式来验证和设置数据。在本教程中,我们将探讨如何使用 Pydantic 的 field_validator 装饰器来创建自定义的字段验证逻辑。

基础知识

在开始之前,请确保您已经安装了 Pydantic。如果没有,请使用以下命令安装:

pip install pydantic

创建 Pydantic 模型

首先,让我们创建一个简单的 Pydantic 模型。这个模型将包含一个名为 a 的字段。

from pydantic import BaseModel
class Model(BaseModel):
    a: str

使用 field_validator 装饰器

field_validator 装饰器允许您为模型中的字段添加自定义验证逻辑。要使用它,请按照以下步骤操作:

  1. 导入 field_validator: 从 pydantic 导入 field_validator
from pydantic import BaseModel, field_validator
  1. 定义验证函数: 创建一个类方法,该方法接受一个参数(要验证的值)并返回验证后的值。
class Model(BaseModel):
    a: str
    @field_validator('a')
    @classmethod
    def ensure_foobar(cls, v: Any):
        if 'foobar' not in v:
            raise ValueError('"foobar" not found in a')
        return v

在这个例子中,我们定义了一个名为 ensure_foobar 的验证函数,它检查 a 字段的值是否包含子字符串 "foobar"
3. 应用装饰器: 使用 @field_validator('field_name') 语法将装饰器应用于验证函数。
4. 测试模型: 创建模型实例并测试验证逻辑。

# 正确的值
model = Model(a='this is foobar good')
print(model)
# 错误的值
try:
    model = Model(a='snap')
except ValidationError as exc_info:
    print(exc_info)

在上面的例子中,第一个模型实例成功创建,因为 a 字段的值包含 "foobar"。第二个实例创建失败,因为值不包含 "foobar",因此抛出了 ValidationError

高级用法

field_validator 装饰器还支持一些高级功能,如:

  • 验证多个字段: 通过传递多个字段名作为参数,可以创建一个验证函数来验证多个字段。
class Model(BaseModel):
    a: str
    b: str
    @field_validator('a', 'b')
    @classmethod
    def validate_fields(cls, v: Any, values: Dict[str, Any]):
        if 'foobar' not in v and 'foobar' not in values.get('b', ''):
            raise ValueError('"foobar" not found in a or b')
        return v
  • 自定义验证模式: 通过设置 mode 参数,可以指定验证是在字段验证前还是验证后进行。
@field_validator('a', mode='before')
  • 检查字段存在性: 通过设置 check_fields 参数,可以控制是否检查字段是否实际存在于模型中。
@field_validator('a', check_fields=False)

源码分析

以下是 field_validator 装饰器的基本结构和关键部分:

def field_validator(
    field: str,
    /,
    *fields: str,
    mode: FieldValidatorModes = 'after',
    check_fields: bool | None = None,
) -> Callable[[Any], Any]:
    # ...

参数解析

  • field: 第一个字段名,作为位置参数传递。/ 表示 field 是一个位置参数,不能作为关键字参数传递。
  • *fields: 其他字段名,作为可变位置参数传递。
  • mode: 指定验证是在字段验证前还是验证后进行。
  • check_fields: 控制是否检查字段是否实际存在于模型中。

关键部分

  1. 参数检查:
    • 检查 field 是否为函数类型。如果是,抛出错误,因为 field_validator 应该用于字段和关键字参数,而不是单独使用。
    • 检查所有字段名是否都是字符串类型。如果不是,抛出错误。
  2. 内部装饰器定义:
    • 定义一个内部函数 dec,它接受一个可调用对象 f 作为参数,并返回一个 PydanticDescriptorProxy 对象。
  3. 验证函数类型:
    • 检查 f 是否是实例方法。如果是,抛出错误,因为 field_validator 不能应用于实例方法。
  4. 确保类方法:
    • 确保 f 是一个类方法。
  5. 创建装饰器信息:
    • 创建一个包含字段信息、模式和字段检查标志的 FieldValidatorDecoratorInfo 对象。
  6. 返回代理对象:
    • 返回一个 PydanticDescriptorProxy 对象,它包装了原始的函数 f 和字段验证信息。

这个装饰器的设计遵循了几个优秀的设计原则:

  • 单一职责原则field_validator只负责字段验证,不处理其他逻辑。
  • 开闭原则:通过使用装饰器模式,可以轻松地扩展或修改字段验证逻辑,而不需要修改原始函数。
  • 代码重用:通过装饰器,可以在多个模型中重用相同的验证逻辑。
    此外,这段代码还展示了一些Python的高级特性,如类型注解、装饰器和元编程。

结论

在本教程中,我们学习了如何使用 Pydantic 的 field_validator 装饰器来为模型字段添加自定义验证逻辑。通过这个强大的工具,您可以确保输入数据符合您的特定要求,从而提高应用程序的健壮性和可靠性。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐