Pydantic 是一个功能强大的 Python 数据验证库,它通过 Python 类型注解实现快速的数据验证和转换。它不仅提供了全面的类型验证、自动数据转换和详细的错误处理机制,还具有基于 Rust 实现的高性能核心验证器。凭借其优秀的 IDE 支持和可扩展性,Pydantic 在 FastAPI 等 Web 框架、配置管理、数据序列化以及 API 接口模型定义等多个场景中得到广泛应用。
pip install pydantic
pip install pydantic-settings
在开始使用 Pydantic 之前,我们需要了解它的核心概念和基本用法。Pydantic 的核心是通过定义模型类来实现数据验证,这些模型类继承自 BaseModel。
基础模型是 Pydantic 中最常用的功能。通过继承 BaseModel 类,我们可以定义数据结构和类型约束。每个字段都可以使用 Python 的类型注解来指定其类型,这些类型会在数据验证时被强制执行。
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
class User(BaseModel):
id: int
username: str
email: str
full_name: Optional[str] = None # 可选字段
created_at: datetime = datetime.now() # 默认值
# 创建实例
user = User(
id=1,
username="john_doe",
email="john@example.com"
)
# 访问数据
print(user.username) # 输出: john_doe
# 转换为字典
user_dict = user.model_dump()
字段定义说明:
• id: int - 必填的整数字段
• username: str - 必填的字符串字段
• email: str - 必填的邮箱字段
• full_name: Optional[str] - 可选的字符串字段,可以为 None
• created_at: datetime - 带默认值的日期时间字段
Pydantic 的数据验证是自动进行的,当创建模型实例时,输入数据会自动根据定义的类型进行验证和转换。如果验证失败,Pydantic 会抛出详细的 ValidationError 异常。
from pydantic import BaseModel, EmailStr, ValidationError
class UserRegistration(BaseModel):
username: str
email: EmailStr
age: int
try:
# 尝试创建无效数据
user = UserRegistration(
username="john",
email="invalid-email", # 无效邮箱
age="not_a_number" # 无效年龄
)
except ValidationError as e:
print("验证错误:")
for error in e.errors():
print(f"- {error['loc'][0]}: {error['msg']}")
当验证失败时,错误信息会包含:
• 具体是哪个字段验证失败
• 失败的原因
• 期望的数据类型
• 实际接收到的数据类型
在实际应用中,数据结构往往是嵌套的。Pydantic 完全支持模型嵌套,这使得我们可以构建复杂的数据结构,同时保持数据验证的严谨性。
from typing import List
class Address(BaseModel):
street: str
city: str
country: str
class User(BaseModel):
name: str
addresses: List[Address]
# 使用嵌套模型
user = User(
name="John Doe",
addresses=[
{"street": "123 Main St", "city": "Boston", "country": "USA"},
{"street": "456 Park Ave", "city": "New York", "country": "USA"}
]
)
嵌套模型的优势:
• 保持数据结构的层次清晰
• 支持复杂的数据验证逻辑
• 方便数据的序列化和反序列化
Pydantic 提供了丰富的验证规则,可以满足各种复杂的数据验证需求。这些规则可以组合使用,构建出强大的验证逻辑。
Field 类是 Pydantic 提供的字段定义工具,它允许我们为字段添加各种验证规则和元数据。通过 Field,我们可以定义字段的约束条件、默认值和描述信息。
from pydantic import BaseModel, Field, EmailStr, HttpUrl, constr
class User(BaseModel):
# 字符串验证
name: str = Field(..., min_length=2, max_length=50) # 必填,长度2-50
username: str = Field(..., pattern="^[a-zA-Z0-9_-]+$") # 只允许字母、数字、下划线和横杠
# 数值验证
age: int = Field(..., ge=0, le=120) # 大于等于0,小于等于120
score: float = Field(..., gt=0, lt=100) # 大于0,小于100
# 特殊类型验证
email: EmailStr # 邮箱验证
website: HttpUrl # URL验证
# 可选字段
description: str | None = Field(None, max_length=1000) # 可选,最大长度1000
验证规则说明:
• min_length/max_length: 控制字符串长度
• pattern: 使用正则表达式验证字符串格式
• ge/le: 大于等于/小于等于
• gt/lt: 大于/小于
from typing import List
class Order(BaseModel):
# 列表长度验证
items: List[str] = Field(..., min_items=1, max_items=10)
# 列表元素唯一性验证
tags: List[str] = Field(..., unique_items=True)
# 价格必须为正数的列表
prices: List[float] = Field(..., gt=0)
from pydantic import BaseModel, model_validator, field_validator
from datetime import datetime
class Order(BaseModel):
order_id: str
created_at: datetime
total_amount: float
items_count: int
# 字段级验证器
@field_validator('order_id')
def validate_order_id(cls, v):
if not v.startswith('ORD-'):
return f'ORD-{v}'
return v
# 模型级验证器
@model_validator(mode='after')
def validate_total(self):
if self.total_amount <= 0 and self.items_count > 0:
raise ValueError('Total amount must be positive when items exist')
return self
from typing import Optional
from pydantic import BaseModel, Field, model_validator
class Product(BaseModel):
name: str
price: float
discount: Optional[float] = None
final_price: Optional[float] = None
@model_validator(mode='after')
def calculate_final_price(self):
if self.discount is not None:
if not 0 <= self.discount <= 1:
raise ValueError('Discount must be between 0 and 1')
self.final_price = self.price * (1 - self.discount)
else:
self.final_price = self.price
return self
from pydantic import BaseModel, Field, EmailStr, HttpUrl, conint, confloat, constr
class UserProfile(BaseModel):
# 受约束的字符串
username: constr(min_length=3, max_length=20, pattern="^[a-zA-Z0-9_]+$")
# 受约束的整数
age: conint(ge=0, le=120)
# 受约束的浮点数
height: confloat(ge=0, le=300)
# 枚举选择
status: str = Field(..., pattern="^(active|inactive|pending)$")
# 布尔值
is_active: bool = True
这些验证规则涵盖了日常开发中最常见的数据验证场景。通过组合使用这些规则,可以构建出复杂的数据验证逻辑。记住几个要点:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool = False
@app.post("/items/")
async def create_item(item: Item):
return item
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
database_url: str
api_key: str
debug: bool = False
model_config = SettingsConfigDict(env_file='.env')
# 从环境变量加载配置
settings = Settings()
# 字典转模型
data = {"name": "John", "age": "25"} # 注意 age 是字符串
user = User.model_validate(data) # 推荐使用 model_validate 而不是 parse_obj
# 模型转 JSON
json_str = user.model_dump_json() # 推荐使用 model_dump_json 而不是 json()
# 模型转字典
user_dict = user.model_dump() # 推荐使用 model_dump 而不是 dict()
# 模型转 JSON 字符串(带缩进)
json_str = user.model_dump_json(indent=4)
# JSON 字符串转模型
user = User.model_validate_json(json_str)
try:
user = User(name="John", age="invalid")
except ValidationError as e:
print("数据无效:", e)