1. 引言
在 Python 开发中,数据校验与解析是几乎每个项目都绕不开的环节。无论是从 API 接收 JSON 请求、读取配置文件,还是与数据库交互,我们都希望数据在进入业务逻辑之前就得到验证和规范化。Pydantic 正是为此而生的现代数据校验库,它基于 Python 类型提示(Type Hints)构建,让数据校验变得简洁、直观且高效。
Pydantic 最初由 Samuel Colvin 于 2017 年创建,如今已成为 Python 生态中最受欢迎的库之一。它不仅是 FastAPI 的数据校验基石,也被广泛应用于数据科学、配置管理、ORM 映射等众多场景。本文将系统介绍 Pydantic 的核心概念与使用方法,帮助你快速上手这一强大的工具。
2. 为什么选择 Pydantic
在 Pydantic 出现之前,Python 开发者通常使用手写校验逻辑或 schema 类库(如 Marshmallow、Schema)来处理数据验证。这些方案各有优劣,但普遍存在代码冗余、类型支持不完善或性能瓶颈等问题。
Pydantic 的核心优势体现在以下几个方面:
- 基于类型提示:直接利用 Python 原生类型注解定义数据模型,无需学习额外的 DSL(领域特定语言)。
- 性能卓越:核心逻辑使用 Rust 编写(Pydantic V2),校验速度远超同类纯 Python 实现。
- 自动类型转换 :在严格校验的同时,能智能地将输入数据转换为目标类型,如将字符串
"123"转为整数123。 - 丰富的验证器:内置大量字段约束(如长度、范围、正则),并支持自定义验证逻辑。
- 序列化与反序列化:轻松实现模型与 JSON、字典之间的相互转换。
- 与生态无缝集成:FastAPI、Django、SQLAlchemy 等主流框架均提供官方或第三方集成。
3. 安装与基础用法
3.1 安装 Pydantic
Pydantic V2 要求 Python 3.8 及以上版本,推荐使用 Python 3.10+。使用 pip 即可完成安装:
bash
pip install pydantic
安装完成后,可以通过以下命令验证版本:
bash
python -c "import pydantic; print(pydantic.__version__)"
3.2 第一个模型
Pydantic 的核心是 BaseModel 基类。我们通过继承它并声明带类型注解的类属性来定义数据模型:
python
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
email: str
创建模型实例时,Pydantic 会自动校验输入数据:
python
user = User(name="张三", age=25, email="zhangsan@example.com")
print(user)
# name='张三' age=25 email='zhangsan@example.com'
如果传入的数据类型不匹配,Pydantic 会尝试进行类型转换:
python
user = User(name="李四", age="30", email="lisi@example.com")
print(user.age, type(user.age))
# 30 <class 'int'>
当数据无法通过校验时,Pydantic 会抛出 ValidationError 异常:
python
from pydantic import ValidationError
try:
User(name="王五", age="abc", email="wangwu@example.com")
except ValidationError as e:
print(e)
4. 字段类型与约束
4.1 常用内置类型
Pydantic 支持 Python 标准库中的绝大多数类型,包括 str、int、float、bool、list、dict、tuple、set 等,同时也支持 typing 模块中的泛型类型:
python
from typing import Optional, List, Dict, Union
from pydantic import BaseModel
class Order(BaseModel):
order_id: int
items: List[str]
metadata: Dict[str, str]
discount: Optional[float] = None
status: Union[str, int] = "pending"
4.2 字段约束
Pydantic 通过 Field 函数为字段添加更细致的约束条件:
python
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str = Field(..., min_length=1, max_length=50)
price: float = Field(..., gt=0, le=10000)
quantity: int = Field(0, ge=0)
description: str = Field(default="", max_length=200)
常用约束参数包括:
min_length/max_length:字符串长度限制gt/ge/lt/le:数值大小限制(大于、大于等于、小于、小于等于)pattern:正则表达式匹配default:默认值default_factory:默认值工厂函数,用于生成动态默认值
4.3 正则表达式校验
python
from pydantic import BaseModel, Field
class Account(BaseModel):
username: str = Field(..., pattern=r"^[a-zA-Z0-9_]{3,20}$")
phone: str = Field(..., pattern=r"^1[3-9]\d{9}$")
5. 高级校验:验证器
5.1 字段级验证器
当内置约束无法满足需求时,可以使用 @field_validator 装饰器编写自定义验证逻辑:
python
from pydantic import BaseModel, field_validator
class Registration(BaseModel):
username: str
password: str
confirm_password: str
@field_validator("username")
@classmethod
def username_not_admin(cls, v: str) -> str:
if v.lower() == "admin":
raise ValueError("用户名不能为 admin")
return v
@field_validator("confirm_password")
@classmethod
def passwords_match(cls, v: str, info) -> str:
if "password" in info.data and v != info.data["password"]:
raise ValueError("两次输入的密码不一致")
return v
5.2 模型级验证器
@model_validator 用于验证整个模型,适合处理字段间相互依赖的逻辑:
python
from pydantic import BaseModel, model_validator
class DateRange(BaseModel):
start_date: str
end_date: str
@model_validator(mode="after")
def check_date_range(self):
if self.start_date > self.end_date:
raise ValueError("开始日期不能晚于结束日期")
return self
6. 数据序列化与解析
6.1 模型转字典与 JSON
python
user = User(name="张三", age=25, email="zhangsan@example.com")
# 转字典
data = user.model_dump()
print(data)
# {'name': '张三', 'age': 25, 'email': 'zhangsan@example.com'}
# 转 JSON 字符串
json_str = user.model_dump_json()
print(json_str)
# {"name":"张三","age":25,"email":"zhangsan@example.com"}
6.2 从字典与 JSON 解析
python
# 从字典创建
data_dict = {"name": "李四", "age": 30, "email": "lisi@example.com"}
user = User.model_validate(data_dict)
# 从 JSON 字符串创建
json_str = '{"name": "王五", "age": 28, "email": "wangwu@example.com"}'
user = User.model_validate_json(json_str)
7. 嵌套模型与复杂结构
Pydantic 支持模型嵌套,非常适合处理层级化的数据结构:
python
from typing import List
from pydantic import BaseModel
class Address(BaseModel):
city: str
street: str
zip_code: str
class Customer(BaseModel):
name: str
address: Address
orders: List[dict] = []
嵌套模型的使用方式与普通模型一致:
python
customer = Customer(
name="赵六",
address={"city": "北京", "street": "中关村大街", "zip_code": "100080"},
orders=[{"order_id": 1, "amount": 99.9}],
)
print(customer.address.city)
# 北京
8. 配置管理:Settings 模型
Pydantic 的 BaseSettings 类(需安装 pydantic-settings 包)非常适合管理应用配置,支持从环境变量、.env 文件等来源自动读取配置:
bash
pip install pydantic-settings
python
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "My App"
debug: bool = False
database_url: str
class Config:
env_file = ".env"
python
settings = Settings()
print(settings.database_url)
9. 实战示例:构建一个用户注册接口
下面结合 FastAPI 展示 Pydantic 在实际项目中的典型用法:
python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr, Field
app = FastAPI()
class UserRegister(BaseModel):
username: str = Field(..., min_length=3, max_length=20)
email: EmailStr
password: str = Field(..., min_length=8)
class UserResponse(BaseModel):
username: str
email: EmailStr
@app.post("/register", response_model=UserResponse)
async def register(user: UserRegister):
# 模拟用户创建逻辑
return UserResponse(username=user.username, email=user.email)
在这个示例中,FastAPI 自动利用 Pydantic 模型完成请求体的解析与校验,并确保响应数据符合 UserResponse 的结构。
10. 总结
Pydantic 凭借其简洁的语法、强大的类型支持和卓越的性能,已成为 Python 数据校验领域的事实标准。本文从基础模型定义、字段约束、验证器、序列化到嵌套模型和配置管理,系统介绍了 Pydantic 的核心功能。
在实际项目中,建议从简单的模型开始,逐步引入验证器和嵌套结构,让数据层始终保持清晰和健壮。结合 FastAPI 等框架使用时,Pydantic 能显著提升开发效率,减少大量重复的校验代码。