Pydantic — Python 最流行的数据验证与序列化库(v2)
一句话说明
Pydantic v2 用 Python 类型提示定义数据模型,自动做类型转换和验证,是 FastAPI 的数据基础,也是替代手写 dataclass + 验证代码的最佳工具。
安装与配置
# pip 安装(v2 已是默认)
pip install pydantic # 当前版本 2.13+(Rust 内核,比 v1 快 5-50x)
# 邮件/URL 验证额外字段
pip install pydantic[email] # EmailStr 需要
# 验证
python -c "import pydantic; print(pydantic.__version__)"
核心用法
基本模型
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import date
# 定义模型(继承 BaseModel)
class Patient(BaseModel):
id: int # 必填整数
name: str # 必填字符串
age: int = Field(ge=0, le=120) # 范围约束
email: Optional[EmailStr] = None # 可选邮箱
diagnosis: str = "未知" # 有默认值
created_at: date = Field(default_factory=date.today) # 动态默认
# 从字典创建(自动验证+转类型)
p = Patient(
id = 1,
name = "张三",
age = "35", # 字符串 "35" 自动转 int
email= "zhangsan@qq.com",
)
print(p.model_dump()) # 转为字典
print(p.model_dump_json())# 转为 JSON 字符串
字段验证器
from pydantic import BaseModel, field_validator, model_validator
class OTUSample(BaseModel):
sample_id: str
shannon: float
n_reads: int
group: str
@field_validator("sample_id") # 字段级验证器
@classmethod
def validate_sample_id(cls, v: str) -> str:
if not v.startswith("S"):
raise ValueError("样本ID必须以 S 开头")
return v.upper() # 也可以转换值
@field_validator("group")
@classmethod
def validate_group(cls, v: str) -> str:
allowed = {"T2D", "健康对照", "IGT"}
if v not in allowed:
raise ValueError(f"group 必须在 {allowed} 中,收到:{v}")
return v
@model_validator(mode="after") # 模型级验证器(跨字段)
def check_shannon_reads_ratio(self) -> "OTUSample":
if self.n_reads < 1000 and self.shannon > 5:
raise ValueError("reads 数太少但 shannon 很高,数据可疑")
return self
嵌套模型
from pydantic import BaseModel
from typing import List
class Gene(BaseModel):
gene_id: str
tpm: float = Field(ge=0) # TPM 非负
class Sample(BaseModel):
sample_id: str
genes: List[Gene] # 嵌套列表(自动递归验证)
metadata: dict = {}
# 从嵌套字典自动解析
data = {
"sample_id": "S001",
"genes": [
{"gene_id": "BRCA1", "tpm": 12.5},
{"gene_id": "TP53", "tpm": 8.3},
]
}
sample = Sample(**data) # 自动递归验证所有嵌套
print(sample.genes[0].gene_id) # BRCA1
实战案例
API 请求/响应模型
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
class CreatePatientRequest(BaseModel):
name: str = Field(min_length=2, max_length=50)
age: int = Field(ge=0, le=150)
bmi: Optional[float] = Field(None, ge=10.0, le=70.0)
diagnosis: str
class PatientResponse(BaseModel):
id: int
name: str
age: int
created_at: datetime
model_config = {"from_attributes": True} # 支持从 ORM 对象创建
# 从 JSON 字符串解析
json_str = '{"name": "李四", "age": 45, "diagnosis": "T2D"}'
req = CreatePatientRequest.model_validate_json(json_str)
# 批量验证列表
patients_data = [{"name": "张三", "age": 30, "diagnosis": "健康"}]
patients = [CreatePatientRequest(**p) for p in patients_data]
常见报错与解决
| 报错 | 原因 | 解决 |
|---|
ValidationError: ... field required | 必填字段未传 | 检查字段名是否正确,或加 Optional |
ValidationError: value is not a valid integer | 类型无法转换 | 检查传入数据类型 |
PydanticUserError: ... v1 style | 混用 v1 和 v2 API | v2 用 model_dump(),不用 dict() |
ImportError: email-validator | 缺少依赖 | pip install pydantic[email] |
速查表
| 操作 | 代码(v2) |
|---|
| 定义模型 | class M(BaseModel): field: type |
| 范围约束 | Field(ge=0, le=100) |
| 长度约束 | Field(min_length=2) |
| 可选字段 | Optional[str] = None |
| 转字典 | m.model_dump() |
| 转 JSON | m.model_dump_json() |
| 从字典创建 | M(**d) 或 M.model_validate(d) |
| 从 JSON 创建 | M.model_validate_json(s) |
| 字段验证器 | @field_validator("field") |
| 模型验证器 | @model_validator(mode="after") |