Pydantic 数据模型:定义、验证和解析一步到位
Pydantic 数据模型:定义、验证和解析一步到位
在现代软件开发中,数据验证和解析是至关重要的环节。无论是处理用户输入、API 请求,还是数据库交互,我们都需要确保数据的有效性和一致性。传统的手动数据验证方法不仅繁琐易错,而且难以维护。幸运的是,Python 生态系统中涌现出许多优秀的库来简化这一过程,其中 Pydantic 以其卓越的性能、类型注解支持和易用性脱颖而出,成为数据验证和解析领域的佼佼者。
本文将深入探讨 Pydantic,详细介绍其核心概念、使用方法和高级特性,帮助您全面掌握这一强大的工具,并将其应用到您的项目中,构建更健壮、更可靠的应用程序。
1. Pydantic 简介:不仅仅是数据验证
Pydantic 是一个基于 Python 类型注解的数据验证和解析库。它允许您使用 Python 类型提示来定义数据模型,并自动执行数据验证、类型转换和文档生成。Pydantic 的核心优势在于:
- 类型驱动: Pydantic 充分利用 Python 类型注解 (Type Hints) 的优势。您只需使用类型注解定义数据结构,Pydantic 就会自动处理数据验证和转换。这不仅简化了代码,还提高了代码的可读性和可维护性。
- 性能卓越: Pydantic 的底层使用了 Cython 进行优化,因此在性能方面表现出色,尤其是在处理大量数据时。它比其他类似的库(如 Marshmallow)快得多。
- 易于使用: Pydantic 的 API 设计简洁直观。您无需学习复杂的 DSL 或配置,只需使用 Python 类型注解即可定义数据模型。
- 自动文档生成: Pydantic 可以根据您定义的数据模型自动生成 JSON Schema 和 OpenAPI/Swagger 文档,方便 API 的开发和维护。
- 强大的错误处理: Pydantic 提供清晰、详细的错误消息,帮助您快速定位和修复数据验证问题。
- 可扩展性: Pydantic 提供了丰富的自定义选项,允许您根据需要扩展其功能,例如自定义验证器、类型转换器等。
- 广泛的应用场景: Pydantic 不仅适用于 Web 开发(例如 FastAPI 框架就深度集成了 Pydantic),还可用于数据科学、机器学习、配置文件处理等各种场景。
2. 定义 Pydantic 模型:类型注解的力量
Pydantic 的核心是数据模型(Model)。您可以通过继承 pydantic.BaseModel
类并使用 Python 类型注解来定义数据模型。让我们从一个简单的例子开始:
```python
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
signup_ts: datetime | None = None
friends: list[int] = []
```
在这个例子中,我们定义了一个名为 User
的 Pydantic 模型。它具有以下字段:
id
: 整数类型,必填字段。name
: 字符串类型,必填字段。signup_ts
:datetime
类型或None
,可选字段,默认值为None
。friends
: 整数列表,可选字段,默认值为空列表。
通过使用类型注解,我们清晰地定义了每个字段的类型和约束。Pydantic 将自动根据这些类型注解进行数据验证和转换。
2.1 常用数据类型
Pydantic 支持多种内置数据类型,包括:
- 基本类型:
int
,float
,str
,bool
,bytes
,datetime
,date
,time
,timedelta
。 - 集合类型:
list
,tuple
,set
,frozenset
,dict
。 - 特殊类型:
Any
,Union
,Optional
,Literal
,UUID
,FilePath
,DirectoryPath
,EmailStr
,UrlStr
等。
您还可以使用嵌套模型来定义复杂的数据结构:
```python
from pydantic import BaseModel
class Address(BaseModel):
street: str
city: str
zip_code: str
class User(BaseModel):
id: int
name: str
address: Address
```
在这个例子中,User
模型包含一个 address
字段,其类型为另一个 Pydantic 模型 Address
。
2.2 字段配置:更精细的控制
除了类型注解,Pydantic 还允许您使用 Field
类对字段进行更精细的配置。Field
类提供了许多参数,用于自定义字段的行为:
```python
from pydantic import BaseModel, Field
class User(BaseModel):
id: int = Field(..., gt=0) # 必须大于 0
name: str = Field(..., min_length=3, max_length=50) # 长度限制
email: str = Field(..., regex=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$") # 正则表达式
age: int | None = Field(None, ge=18, le=120) # 可选,年龄范围 18-120
description: str | None = Field(None, alias="desc") #别名
password: str = Field(..., exclude=True) #从模型导出中排除
```
Field
类的常用参数包括:
default
: 字段的默认值。default_factory
: 一个 callable 对象, 用于生成默认值. 与default
互斥.alias
: 字段的别名,用于在解析数据时使用不同的名称。title
: 字段的标题,用于生成文档。description
: 字段的描述,用于生成文档。const
: 字段必须等于该值.gt
: 字段必须大于该值 (greater than)。ge
: 字段必须大于或等于该值 (greater than or equal to)。lt
: 字段必须小于该值 (less than)。le
: 字段必须小于或等于该值 (less than or equal to)。min_length
: 字符串或列表的最小长度。max_length
: 字符串或列表的最大长度。regex
: 字符串必须匹配的正则表达式。exclude
: 在模型导出 (如dict()
,json()
) 时是否排除该字段。
2.3 自定义验证器:扩展 Pydantic 的功能
Pydantic 提供了两种类型的自定义验证器:
@validator
装饰器: 用于定义字段级别的验证器。@root_validator
装饰器: 用于定义模型级别的验证器。
2.3.1 @validator
:字段级验证
@validator
装饰器用于定义一个函数,该函数将在字段赋值之前被调用。您可以使用它来执行自定义验证逻辑,例如检查值是否在特定范围内、是否符合特定格式等。
```python
from pydantic import BaseModel, validator
class User(BaseModel):
name: str
age: int
@validator("age")
def age_must_be_positive(cls, value):
if value <= 0:
raise ValueError("Age must be positive")
return value
```
在这个例子中,age_must_be_positive
函数是一个字段级验证器,它检查 age
字段的值是否为正数。如果不是,它将引发 ValueError
异常。
@validator
装饰器还支持一些可选参数:
pre
: 如果设置为True
,验证器将在 Pydantic 的内置类型转换之前运行。默认为False
.each_item
: 如果字段是集合类型(如list
),是否对每个元素应用验证器, 默认False
.always
: 是否始终运行验证器,即使字段没有被赋值。默认False
.check_fields
: 是否检查字段是否存在。默认True
.
2.3.2 @root_validator
:模型级验证
@root_validator
装饰器用于定义一个函数,该函数将在整个模型验证完成后被调用。您可以使用它来执行跨字段的验证逻辑,例如检查多个字段之间的关系是否满足特定条件。
```python
from pydantic import BaseModel, root_validator
class Event(BaseModel):
start_time: datetime
end_time: datetime
@root_validator
def end_time_must_be_after_start_time(cls, values):
if "start_time" in values and "end_time" in values and values["start_time"] >= values["end_time"]:
raise ValueError("End time must be after start time")
return values
``
@root_validator装饰器也有
pre参数, 如果设置为
True`, 将在所有字段验证之前运行.
在这个例子中,end_time_must_be_after_start_time
函数是一个模型级验证器,它检查 end_time
是否晚于 start_time
。
3. 数据验证与解析:Pydantic 的核心功能
定义好 Pydantic 模型后,您就可以使用它来验证和解析数据了。Pydantic 提供了多种方法来完成这一任务:
3.1 构造函数:直接创建模型实例
最简单的方法是使用模型的构造函数来创建实例:
```python
data = {
"id": 123,
"name": "John Doe",
"signup_ts": "2023-10-27T10:00:00",
"friends": [1, 2, 3],
}
user = User(**data)
print(user.id) # 输出:123
print(user.signup_ts) # 输出:2023-10-27 10:00:00
```
Pydantic 将自动根据模型定义进行数据验证和类型转换。如果数据无效,Pydantic 将引发 ValidationError
异常。
3.2 parse_obj
方法:从字典解析
parse_obj
方法用于从字典创建模型实例:
```python
data = {
"id": 123,
"name": "John Doe",
"signup_ts": "2023-10-27T10:00:00",
"friends": [1, 2, 3],
}
user = User.parse_obj(data)
```
parse_obj
方法与构造函数类似,但它更明确地表明您正在从字典解析数据。
3.3 parse_raw
方法:从 JSON 字符串或文件解析
parse_raw
方法用于从 JSON 字符串或文件创建模型实例:
```python
json_data = '{"id": 123, "name": "John Doe", "signup_ts": "2023-10-27T10:00:00", "friends": [1, 2, 3]}'
user = User.parse_raw(json_data)
也可以传入文件路径
user = User.parse_raw("path/to/file.json")
```
3.4 parse_file
方法:从文件路径解析
parse_file
方法用于直接从文件路径创建模型实例
```python
user = User.parse_file("path/to/file.json")
```
3.5 ValidationError
异常:处理验证错误
如果数据无效,Pydantic 将引发 ValidationError
异常。该异常包含有关验证失败的详细信息,包括错误消息和字段路径。
```python
from pydantic import BaseModel, ValidationError
class User(BaseModel):
id: int
name: str
try:
user = User(id="abc", name="John Doe")
except ValidationError as e:
print(e)
```
输出:
1 validation error for User
id
value is not a valid integer (type=type_error.integer)
您可以使用 e.errors()
方法获取一个包含所有验证错误的列表。每个错误都是一个字典,包含以下键:
loc
: 错误的位置(字段路径)。msg
: 错误消息。type
: 错误类型。
您还可以使用 e.json()
方法将错误信息转换为 JSON 格式。
4. 模型导出:将数据转换为字典或 JSON
Pydantic 模型提供了多种方法将数据转换为字典或 JSON 格式,方便与其他系统进行交互:
4.1 dict
方法:转换为字典
dict
方法用于将模型实例转换为字典:
```python
user = User(id=123, name="John Doe")
user_dict = user.dict()
print(user_dict) # 输出:{'id': 123, 'name': 'John Doe'}
``
dict方法接受许多参数来定制输出. 常用参数有:
include
*: 包含的字段.
exclude
*: 排除的字段.
by_alias
*: 是否使用别名.
exclude_unset
*: 是否排除未设置的字段.
exclude_defaults
*: 是否排除默认值的字段.
exclude_none`: 是否排除值为 None 的字段.
*
4.2 json
方法:转换为 JSON 字符串
json
方法用于将模型实例转换为 JSON 字符串:
```python
user = User(id=123, name="John Doe")
user_json = user.json()
print(user_json) # 输出:{"id": 123, "name": "John Doe"}
``
json方法接受
dict方法的所有参数, 以及
indent,
separators等
json.dumps` 方法的参数.
5. 高级特性:解锁 Pydantic 的更多潜力
除了上述核心功能外,Pydantic 还提供了许多高级特性,进一步增强了其灵活性和适用性:
5.1 泛型模型:支持泛型类型
Pydantic 支持泛型模型,允许您定义可以处理不同类型数据的模型。
```python
from typing import Generic, TypeVar, List
from pydantic.generics import GenericModel
T = TypeVar('T')
class ItemList(GenericModel, Generic[T]):
items: List[T]
```
在这个示例中我们定义了一个泛型模型 ItemList
,它可以用于处理任何类型 T
的列表。
5.2 Config 类:全局配置
Pydantic 允许您通过 Config
类来配置模型的行为。Config
类可以作为 Pydantic 模型的内部类,也可以通过model_config
属性访问。
```python
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
class Config:
# 或者使用 model_config = { ... }
orm_mode = True # 启用 ORM 模式
allow_population_by_field_name = True #允许按字段名填充
```
Config
类的常用选项包括:
orm_mode
: 启用 ORM 模式,允许从 ORM 对象创建模型实例。allow_mutation
: 是否允许修改模型实例的字段值.error_msg_templates
: 自定义错误消息模板。extra
: 如何处理模型定义中未定义的字段 (allow
,ignore
,forbid
)。json_encoders
: 自定义 JSON 编码器。validate_all
: 是否验证所有字段, 即使依赖的字段有错误, 默认False
.validate_assignment
: 是否在赋值时进行验证, 默认False
.
5.3 数据转换: 使用 BeforeValidator
, AfterValidator
, WrapValidator
和 PlainValidator
从 Pydantic v2 开始, 引入了 @pydantic.field_validator
装饰器, 以及 BeforeValidator
, AfterValidator
, WrapValidator
和 PlainValidator
, 允许用户对数据进行更精细的转换和验证.
BeforeValidator
: 在 Pydantic 进行类型校验和 coercion 之前执行.AfterValidator
: 在 Pydantic 进行类型校验和 coercion 之后执行.WrapValidator
: 同时包含 before 和 after 逻辑.PlainValidator
: 接收原始输入值.
```python
from typing import Any
from pydantic import BaseModel, BeforeValidator, AfterValidator, ValidationError
def to_upper(v: str) -> str:
return v.upper()
def double_value(v: int) -> int:
return v * 2
class MyModel(BaseModel):
name: str = BeforeValidator(to_upper)
value: int = AfterValidator(double_value)
m = MyModel(name='hello', value=5)
print(m)
> name='HELLO' value=10
```
6. 总结:Pydantic 的优势与应用
Pydantic 是一个功能强大且易于使用的 Python 数据验证和解析库。它通过类型注解简化了数据模型的定义,并自动执行数据验证、类型转换和文档生成。Pydantic 的高性能、可扩展性和广泛的应用场景使其成为构建健壮、可靠的应用程序的理想选择。
通过本文的介绍,您应该已经对 Pydantic 的核心概念、使用方法和高级特性有了全面的了解。希望您能够将 Pydantic 应用到您的项目中,提高开发效率和代码质量。