跳转至

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 APIv2 用 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()
转 JSONm.model_dump_json()
从字典创建M(**d)M.model_validate(d)
从 JSON 创建M.model_validate_json(s)
字段验证器@field_validator("field")
模型验证器@model_validator(mode="after")