Pydantic:目前最流行的Python数据验证库

前言

在处理来自系统外部的数据,如API、终端用户输入或其他来源时,我们必须牢记开发中的一条基本原则:“永远不要相信用户的输入”。

因此,我们必须对这些数据进行严格的检查和验证,确保它们被适当地格式化和标准化。这样做的目的是为了确保这些数据符合我们的程序所需的输入规范,从而保障项目能够正确且高效地运行。

为什么使用 Python 的 Pydantic 库?

Pydantic 是一个在 Python 中用于数据验证和解析的第三方库,它现在是 Python 使用最广泛的数据验证库

  • 它利用声明式的方式定义数据模型Python 类型提示的强大功能来执行数据验证和序列化,使您的代码更可靠、更可读、更简洁且更易于调试。。
  • 它还可以从模型生成 JSON 架构,提供了自动生成文档等功能,从而轻松与其他工具集成。

Pydantic 在很多优秀的项目中被广泛使用。

Pydantic 的一些主要特性

易用性

Pydantic 使用起来简单直观,需要最少的样板代码和配置。它适用于许多流行的 IDE 和静态分析工具,例如 PyCharm、VS Code、mypy 等。Pydantic 可以轻松与其他流行的 Python 库(如 Flask、Django、FastAPI 和 SQLAlchemy)集成,使其易于在现有项目中使用。


类型注解

Pydantic 使用类型注解来定义模型的字段类型,以确保确保数据符合预期的类型和格式。你可以使用Python 内置的类型自定义类型或者其他Pydantic 提供的验证类型


数据验证,用户友好的错误

Pydantic 自动根据模型定义进行数据验证。它会检查字段的类型、长度、范围等,并自动报告验证错误,Pydantic 会提供信息丰富且可读的错误消息,包括错误的位置、类型和输入。你可以使用 ValidationError 异常来捕获验证错误。


序列化与反序列化

Pydantic 提供了从各种数据格式(例如 JSON、字典)到模型实例的转换功能。它可以自动将输入数据解析成模型实例,并保留类型安全性和验证规则。


性能高

Pydantic 的核心验证逻辑是用 Rust 编写的,使其成为 Python 中最快的数据验证库之一。它还支持延迟验证和缓存,以提高效率。

Pydantic和内置的dataclasses非常的像,主要区别在于Pydantic拥有更加强大的数据验证和序列化功能。


安装

安装 Pydantic 非常简单:

pip install pydantic[email]  # 会用到邮箱校验,直接在这一起安装了

如何使用 Pydantic?

使用 Pydantic 的主要方法是创建继承自 BaseModel 的自定义类,这是所有 Pydantic 模型的基类。然后,您可以使用类型注释定义模型的属性,并选择性地提供默认值或验证器。

pydantic的核心是模型(Model)

例如,让我们为用户创建一个简单的模型,并使用 Python 的类型注解来声明期望的数据类型:

#! -*-conding: UTF-8 -*-
# @公众号: 海哥python
from enum import Enum

from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, ValidationError, EmailStr
# 导入pydantic对应的模型基类
from pydantic import constr, conint


class GenderEnum(str, Enum):
    """
    性别枚举
    """
    male = "男"
    female = "女"


class User(BaseModel):
    id: int
    name: str = "小卤蛋"
    age: conint(ge=0, le=99)  # 整数范围:0 <= age <= 99
    email: EmailStr
    signup_ts: Optional[datetime] = None
    friends: List[str] = []
    password: constr(min_length=6, max_length=10)  # 字符长度
    phone: constr(pattern=r'^1\d{10}$')  # 正则验证手机号
    sex: GenderEnum  # 枚举验证, 能传: 男和女

我们定义了一个名为User的类,继承自BaseModel。

  • id属性是整型,且是必需的,表示用户ID。
  • name属性是字符串类型,默认值为’小卤蛋’。
  • age属性是整型,且是必需的,表示用户年龄。
  • email属性是电子邮件地址类型。
  • signup_ts属性是可选的日期时间类型,默认值为None,表示用户注册时间。
  • friends属性是字符串列表类型,默认值为空列表,表示用户的朋友列表。
  • sex属性是枚举类型,可选值为“男”或“女”,表示用户的性别。

验证数据

一旦你定义了模型,你可以使用它来验证数据。

如果要从字典实例化 User 对象,可以使用字典对象解包或者.model_validate().model_validate_json()类方法:

if __name__ == '__main__':

    user_data = {
   
        "id": 123,
        "name": "小卤蛋",
        "age": 20,
        "email": "xiaoludan@example.com",
        'signup_ts': '2024-07-19 00:22',
        'friends': ["公众号:海哥python", '小天才', b''],
        'password': '123456',
        'phone': '13800000000',
        'sex': '男'
    }

    try:
        # user = User(**user_data)
        user = User.model_validate(user_data)
        print(f"User id: {
     user.id}, User name: {
     user.name}, User email: {
     user.email}")
    except ValidationError as e:
        print(f"Validation error: {
     e.json()}")

都符合模型定义的情况下,您可以像往常一样访问模型的属性:

User id: 123, User name: 小卤蛋, User email: xiaoludan@example.com

如果数据不符合模型的定义(以下故意不传 id 字段),Pydantic 将抛出一个 ValidationError。

if __name__ == '__main__':

    user_data = {
   
        # "id": 123,
        "name": "小卤蛋",
        "age": 20,
        "email": "xiaoludan@example.com",
        'signup_ts': '2024-07-19 00:22',
        'friends': ["公众号:海哥python", '小天才', b''],
        'password': '123456',
        'phone': '13800000000',
        'sex': '男'
    }

    try:
        # user = User(**user_data)
        user = User.model_validate(user_data)
        print(f"User id: {
     user.id}, User name: {
     user.name}, User email: {
     user.email}")
    except ValidationError as e:
        print(f"Validation error: {
     e.json()}")

报错:

Validation error: [{
   "type":"missing","loc":["id"],"msg":"Field required","input":{
   "name":"小卤蛋","age":20,"email":"xiaoludan@example.com","signup_ts":"2024-07-19 00:22","friends":["公众号:海哥python","小天才",""],"password":"123456","phone":"13800000000","sex":"男"},"url":"https://errors.pydantic.dev/2.8/v/missing"}]

自定义验证

除了内置的验证器,还可以为模型定义自定义验证器。假设要确保用户年龄在18岁以上,可以使用@field_validator装饰器创建一个自定义验证器:

# ! -*-conding: UTF-8 -*-
# @公众号: 海哥python
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel, EmailStr, field_validator, ValidationError


def check_name(v: str) -> str:
    """Validator to be used throughout"""
    if not v.startswith("小"):
        raise ValueError("must be startswith 小")
    return v


class User(BaseModel):
    id: int
    name: str = "小卤蛋"
    age: int
    email: EmailStr
    signup_ts: Optional[datetime] = None
    friends: List[str] = []

    validate_fields = field_validator("name")(check_name)

    @field_validator("age")
    @classmethod
    def check_age(cls, age):
        if age < 18:
            raise ValueError("用户年龄必须大于18岁")
        return age

当尝试创建一个只有12岁的小朋友用户:

if __name__ == '__main__':
    user_data = {
   
        "id": 123,
        "name": "小卤蛋",
        "age": 12,
        "email": "xiaoludan@example.com",
        'signup_ts': '2024-07-19 00:22',
        'friends': ["公众号:海哥python", '小天才', b''],
    }
    try:
        user = User(**user_data)
    except ValidationError as e:
        print(f"Validation error: {
     e.json()}")

将得到一个错误:

Validation error: [{
   "type":"value_error","loc":["age"],"msg":"Value error, 用户年龄必须大于18岁","input":12,"ctx":{
   "error":"用户年龄必须大于18岁"},"url":"https://errors.pydantic.dev/2.8/v/value_error"}]

或者,当name不是开头的话:

if __name__ == '__main__':
    user_data = {
   
        "id": 123,
        "name": "大卤蛋",
        "age": 20,
        "email": "xiaoludan@example.com",
        'signup_ts': '2024-07-19 00:22',
        'friends': ["公众号:海哥python", '小天才', b''],
    }
    try:
        user = User(**user_data)
    except ValidationError as e:
        print(f"Validation error: {
     e.json()}")

将得到报错:

Validation error: [{
   "type":"value_error","loc":["name"],"msg":"Value error, must be startswith 小","input":"大卤蛋","ctx":{
   "error":"must be startswith 小"},"url":"https://errors.pydantic.dev/2.8/v/value_error"}]

如果要同时动态校验多个字段,还可以使用model_validator装饰器。

# ! -*-conding: UTF-8 -*-
# @公众号: 海哥python
from datetime 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海哥python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值