一、Pydantic简介
Pydantic 是一个用于数据验证和设置管理的Python库,它使用类注解来定义数据模型。通过 Pydantic,可以轻松地创建、验证和操作复杂的数据结构,同时提供清晰的错误信息。
官方文档:https://docs.pydantic.dev/latest/api/base_model/
为什么使用Pydantic?
在Python中,类型提示是可选的,这意味着开发者可以声明变量的类型,但Python解释器不会强制执行这些类型。这在开发过程中可能会导致一些难以追踪的错误。Pydantic通过强制类型检查来解决这个问题,它提供了一种更加严格的方式来处理数据验证。
安装Pydantic:
官方文档:https://docs.pydantic.dev/latest/install/
pip install pydantic
# with the `email` extra:
pip install 'pydantic[email]'
# or with `email` and `timezone` extras:
pip install 'pydantic[email,timezone]'
扩展类型安装:https://docs.pydantic.dev/latest/migration/#color-and-payment-card-numbers-moved-to-pydantic-extra-types
pip install pydantic_extra_types
二、工作原理
Pydantic 的核心原理是基于 Python 类型注解 和 数据验证:
- 类型注解:通过在类属性上添加类型注解(如 id: int),Pydantic 知道每个字段应该是什么类型的数据。
- 数据验证:当你传递数据给模型实例时,Pydantic 会根据类型注解和 Field 中的配置自动进行验证。如果数据不符合要求,它会抛出 ValidationError 并提供详细的错误信息。
- 自动转换:Pydantic 还可以尝试将数据自动转换为目标类型。例如,字符串形式的时间戳会被转换为 datetime 对象。
三、数据模型
定义一个继承自 BaseModel 的类来创建数据模型。这个类中的每个属性(字段)都代表模型的一部分,并且可以指定其类型和默认值。
如下示例,创建一个用户模型:
class User(BaseModel):
id: int #必须是整数
name: str = "CYX" # 字符串类型,默认值为 "CYX"。
signup_ts: datetime = None # 可选的时间戳,默认值为 None。
通过实例化模型类来验证传入的数据是否符合预期格式。如果数据不符合要求,Pydantic 会抛出详细的错误信息。
继续以上面的用户模型示例:
user_data = {
"id": 123,
"name": "Alice",
"signup_ts": "2023-10-01T12:00:00"
}
try:
user = User(**user_data)
print(user)
except ValueError as e:
print(e)
在这个例子中,user_data 是一个字典,包含了要验证的数据。通过 User(**user_data) 实例化 User 模型时,Pydantic 会自动验证这些数据是否符合模型定义的要求。
当数据验证失败时,Pydantic会抛出ValidationError。你可以通过try except捕获这个异常。
TIP:** 是 Python 中的字典解包操作符。在 Python 中,当你有一个字典,并且你想将其键值对作为关键字参数传递给一个函数或类构造函数时,可以使用 ** 操作符。这使得你可以避免手动将每个键值对传递给构造函数。
四、使用 Field 添加更多配置
Field 函数可以为字段提供更多的配置选项,如默认值、别名、描述等。
示例:使用 Field 添加约束
class User(BaseModel):
id: int = Field(..., description="用户ID", gt=0) # ID 必须大于0
name: str = Field("John Doe", title="用户名", max_length=50) # 名称最大长度为50
signup_ts: datetime = Field(None, alias="signupTimestamp") # 别名为 signupTimestamp,默认值为 None
TIP:... 是 Python 的省略符(Ellipsis),表示“此处没有默认值”。在这里表示该字段是必填项,必须提供有效的值。如果你不提供这个字段的值,Pydantic 会抛出验证错误。
五、自定义验证器
你可以为模型字段添加自定义验证逻辑,确保数据不仅符合类型要求,还满足特定的业务规则。
实现方式:通过在方法上添加@field_validator实现自定义的验证器
如下依然以用户模型为例,添加自定义验证器:
from pydantic.functional_validators import field_validator
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
age: int
@field_validator('age')
def check_age(cls, v):
if v < 0:
raise ValueError('年龄不能为负数')
return v
在这个例子中,check_age 方法是一个自定义验证器,它会在 age 字段被设置时自动调用,确保年龄不为负数。
更多验证方式,可以查看官方文档:https://docs.pydantic.dev/latest/concepts/validators/
六、复杂类型
Pydantic 支持 Python 内置的复杂类型,如列表、字典、集合等,并且可以嵌套使用。你还可以为这些复杂类型添加约束条件。
示例代码,演示列表和字典:
from typing import List,Dict
from pydantic import BaseModel
class User(BaseModel):
id: int
hobbies: List[str] # 必须是字符串列表
metadata: Dict[str, str] # 键和值都必须是字符串
user_data = {
"id": 123,
"hobbies": ["reading", "coding", "traveling"],
"metadata": {"role": "admin", "status": "active"}
}
user = User(**user_data)
print(user)
Pydantic 也支持与 Python 的 Enum 类结合使用,以确保字段值在预定义的范围内。
from enum import Enum
from pydantic import BaseModel
class Role(str, Enum):
ADMIN = "admin"
USER = "user"
class User(BaseModel):
id: int
role: Role
user_data = {
"id": 123,
"role": "admin"
}
user = User(**user_data)
print(user)
七、自定义类型
Pydantic 允许你定义自己的数据类型,以便更好地满足特定需求。你可以通过继承 BaseModel 或者使用 con* 系列函数来创建自定义类型。
7.1、自定义类
可以通过继承 BaseModel 来创建自定义类,并为其添加验证逻辑。
自定义类也能正常嵌套到其他数据模型中,示例如下:
from pydantic import BaseModel
from pydantic.functional_validators import field_validator
from typing import List
class CustomType(BaseModel):
items: List[int]
@field_validator('items')
def check_items(cls, items):
for v in items:
if v < 0:
raise ValueError('所有项必须是非负数')
return v
class User(BaseModel):
id: int
custom_field: CustomType
user_data = {
"id": 123,
"custom_field": {"items": [1, 2, 3]}
}
user = User(**user_data)
print(user)
7.2、使用 con* 函数创建自定义类型
Pydantic 提供了一系列 con* 函数(如 constr, conint, confloat 等),用于创建带约束的自定义类型。
示例:定义带约束的字符串字段
from pydantic import BaseModel, constr
# 定义一个最小长度为3,最大长度为50的字符串类型
Username = constr(min_length=3, max_length=50)
class User(BaseModel):
id: int
username: Username
user_data = {
"id": 123,
"username": "alice"
}
user = User(**user_data)
print(user)
7.3、使用正则表达式进行验证
Pydantic 还支持使用正则表达式来验证字符串格式。
示例:使用正则表达式验证邮箱地址
from pydantic import BaseModel, constr
EmailStr = constr(pattern=r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+")
class User(BaseModel):
id: int
email: EmailStr
user_data = {
"id": 123,
"email": "alice@example.com"
}
user = User(**user_data)
print(user)
八、Pydantic内置实用类型
Pydantic 提供了许多内置的实用类型,这些类型不仅简化了数据验证的过程,还提供了清晰的错误信息。
8.1、字符串相关类型
- EmailStr:用于验证电子邮件地址。
- HttpUrl:用于验证 HTTP 或 HTTPS URL。
- AnyUrl:用于验证任意 URL(包括 FTP、SFTP 等)。
- AnyHttpUrl:用于验证任意 HTTP 或 HTTPS URL(不区分大小写)。
- PostgresDsn:用于验证 PostgreSQL 数据库连接字符串。
- RedisDsn:用于验证 Redis 数据库连接字符串。
- FilePath:用于验证文件路径(必须是现有文件)。
- DirectoryPath:用于验证目录路径(必须是现有目录)。
- Json:用于验证 JSON 字符串。
示例如下:
from pydantic import BaseModel, EmailStr, HttpUrl, FilePath, Json
class User(BaseModel):
email: EmailStr
website: HttpUrl
config_file: FilePath
settings: Json
user_data = {
"email": "alice@example.com",
"website": "https://example.com",
"config_file": "/path/to/config.json",
"settings": '{"theme": "dark", "notifications": true}'
}
user = User(**user_data)
print(user)
8.2、数字相关类型
- conint:用于定义带约束的整数(如最小值、最大值等)。
- confloat:用于定义带约束的浮点数(如最小值、最大值、精度等)。
- PositiveInt:用于验证正整数。
- NegativeInt:用于验证负整数。
- NonNegativeInt:用于验证非负整数。
- NonPositiveInt:用于验证非正整数。
- PositiveFloat:用于验证正浮点数。
- NegativeFloat:用于验证负浮点数。
- NonNegativeFloat:用于验证非负浮点数。
- NonPositiveFloat:用于验证非正浮点数。
示例代码如下:
from pydantic import BaseModel, conint, confloat, PositiveInt, NegativeFloat
class Data(BaseModel):
age: conint(gt=0, le=120) # 年龄必须大于0且小于等于120
score: confloat(ge=0, le=100) # 分数必须在0到100之间
positive_age: PositiveInt # 正整数
negative_score: NegativeFloat # 负浮点数
data = {
"age": 30,
"score": 85.5,
"positive_age": 42,
"negative_score": -10.5
}
validated_data = Data(**data)
print(validated_data)
8.3、时间和日期类型
- datetime:用于验证 Python 的 datetime.datetime 对象。
- date:用于验证 Python 的 datetime.date 对象。
- time:用于验证 Python 的 datetime.time 对象。
- timedelta:用于验证 Python 的 datetime.timedelta 对象。
- PastDate:用于验证过去的日期(即早于当前日期)。
- FutureDate:用于验证未来的日期(即晚于当前日期)。
示例代码:
from pydantic import BaseModel, PastDate, FutureDate
from datetime import date, datetime
class Event(BaseModel):
start_date: PastDate # 必须是过去的日期
end_date: FutureDate # 必须是未来的日期
event_data = {
"start_date": date(2022, 1, 1),
"end_date": date(2024, 12, 31)
}
event = Event(**event_data)
print(event)
8.4、其他类型
- UUID1, UUID3, UUID4, UUID5:用于验证不同版本的 UUID。
- PyObject:用于验证 Python 可调用对象(如函数或类)。
- StrictStr:用于严格验证字符串(不允许隐式转换)。
- StrictBool:用于严格验证布尔值(不允许隐式转换)。
- StrictInt:用于严格验证整数(不允许隐式转换)。
- StrictFloat:用于严格验证浮点数(不允许隐式转换)。
- StrictBytes:用于严格验证字节序列(不允许隐式转换)。
- PaymentCardNumber:用于验证支付卡号(如信用卡号)。
- Color:用于验证颜色(支持多种格式,如 #ff0000 或 red)。
示例代码:
from pydantic import BaseModel, UUID4
from pydantic_extra_types.color import Color
from pydantic_extra_types.payment import PaymentCardNumber
class Product(BaseModel):
id: UUID4
card_number: PaymentCardNumber
color: Color
product_data = {
"id": "550e8400-e29b-41d4-a716-446655440000",
"card_number": "4242424242424242",
"color": "red"
}
product = Product(**product_data)
print(product)
全部评论