在 Python 数据处理、API 开发和配置管理中,数据验证和序列化是不可或缺的环节。Pydantic V2 凭借其基于 Rust 的高性能核心、简洁的声明式模型和强大的类型约束,已成为 Python 生态中数据层的事实标准。本文将从 Pydantic V2 的基础入手,逐步深入自定义验证器、配置类、嵌套模型以及与 FastAPI 的集成,助你彻底掌握这一现代化数据建模利器。
一、Pydantic V2 的核心变化与安装
Pydantic V2 使用 Rust 编写的 pydantic-core 作为解析引擎,性能相比 V1 提升了 5 到 50 倍,同时保留了用户友好的声明式 API。主要变化包括:验证器使用 @field_validator 和 @model_validator 替代旧的 @validator,配置管理通过 model_config 字典实现,以及更严格的数据转换规则。
安装 Pydantic V2:
pip install pydantic
导入所需模块:
from pydantic import BaseModel, Field, field_validator, model_validator
from typing import Optional, List
from datetime import datetime
二、从简单模型开始:定义第一个 Pydantic 模型
所有 Pydantic 模型都继承自 BaseModel。通过类型注解定义字段,创建实例时自动进行类型强制转换和验证。
class User(BaseModel):
id: int
name: str
email: str
age: int = Field(ge=18, le=120, description="用户年龄必须在18到120之间")
created_at: datetime = Field(default_factory=datetime.now)
# 创建实例
user_data = {
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"age": "25" # 字符串 "25" 会自动转换为整数 25
}
user = User(**user_data)
print(user.model_dump()) # V2 改用 model_dump() 替代 dict()
如果传入的数据不符合约束(例如 age: 15),会立即抛出 ValidationError 并附带清晰的位置信息。
三、高级字段类型与嵌套模型
Pydantic 支持丰富的类型:HttpUrl、EmailStr、PastDate 等,并可通过 Field 设置默认值、别名和校验规则。
from pydantic import HttpUrl, EmailStr
class Address(BaseModel):
street: str
city: str
country: str = "中国"
class UserProfile(BaseModel):
username: str
email: EmailStr # 需要安装 email-validator: pip install email-validator
website: Optional[HttpUrl] = None
addresses: List[Address] = []
tags: List[str] = []
# 嵌套使用
profile = UserProfile(
username="bob",
email="bob@example.com",
website="https://bob.dev",
addresses=[{"street": "人民路1号", "city": "上海"}]
)
print(profile.model_dump())
四、自定义验证器:字段级与模型级
V2 中字段级验证使用 @field_validator,可以访问字段值和验证上下文。例如,强制将用户名转换为小写:
class User(BaseModel):
username: str
password: str
confirm_password: str
@field_validator('username')
@classmethod
def username_lower(cls, v: str) -> str:
return v.lower().strip()
# 模型级验证:检查密码是否一致
@model_validator(mode='after')
def check_passwords_match(self):
if self.password != self.confirm_password:
raise ValueError('密码和确认密码不一致')
return self
mode='after' 表示在字段验证之后运行,可以访问所有已解析的字段值。
五、配置管理与Settings管理
Pydantic 提供了 BaseSettings 用于从环境变量或 .env 文件读取配置,非常适合管理应用设置。
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8')
APP_NAME: str = "MyApp"
DEBUG: bool = False
DATABASE_URL: str
SECRET_KEY: str
@field_validator('SECRET_KEY')
@classmethod
def check_secret_key(cls, v: str) -> str:
if len(v) < 16:
raise ValueError('SECRET_KEY 至少需要16个字符')
return v
# 读取配置(自动从环境变量或 .env 文件加载)
settings = Settings()
print(settings.APP_NAME)
该 Settings 类会按优先级查找环境变量,再查找 .env 文件,未设置则使用默认值。
六、与 FastAPI 无缝集成
FastAPI 全面使用 Pydantic 模型进行请求体验证、查询参数定义和响应序列化。只需将模型作为参数即可自动生成 OpenAPI 文档并进行数据校验。
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class ItemCreate(BaseModel):
name: str
price: float = Field(gt=0)
stock: int = Field(default=0, ge=0)
@app.post("/items")
async def create_item(item: ItemCreate):
# item 已经是经过验证的 Pydantic 模型实例
return {"message": "商品已创建", "item": item.model_dump()}
客户端发送的 JSON 数据会被自动解析为 ItemCreate 实例,如果校验失败直接返回 422 错误详情。
七、性能优化与最佳实践
- 使用 model_validate 而非直接构造:调用
Model.model_validate(data)可以明确触发验证,而直接Model(data)在某些边界情况下可能跳过部分校验。 - 冻结模型:在
model_config中设置frozen=True使得模型不可变,适合当作数据对象。 - 惰性解析:对于大模型,使用
model_validate_json()直接解析 JSON 字符串,避免二次转换。 - 严格模式:设置
strict=True禁止类型强制转换,仅在字段类型精确匹配时才通过验证。
class StrictUser(BaseModel):
model_config = dict(strict=True)
name: str
score: int
# 下面会报错,因为 "100" 不会自动转换为 int
# StrictUser(name="test", score="100")
八、总结
本文通过从基础到进阶的完整案例,展示了 Pydantic V2 在数据验证、配置管理和 API 开发中的强大能力。无论是个人项目还是企业级应用,引入 Pydantic 都能显著减少手动校验代码,提升系统的健壮性和可维护性。随着 Python 类型生态的日趋完善,掌握 Pydantic 已经成为每个 Python 开发者的必备技能。现在,就开始在你的下一个项目中用 Pydantic V2 定义出清晰、安全的数据模型吧。

