本文将详细介绍 Pydantic 模型 和 BaseModel 的核心概念,并通过实际代码示例如何从零开始编写自己的 Pydantic 模型。
1. Pydantic 是什么?
Pydantic 是一个 Python 库,主要用于:
- 数据验证:确保输入数据符合预期的类型和约束。
- 数据解析:将 JSON、字典等原始数据转换为 Python 对象。
- 文档生成:自动生成 API 文档(如 Swagger/OpenAPI)。
- 配置管理:安全地加载环境变量或配置文件。
2. BaseModel:所有模型的基类
Pydantic 的所有模型都继承自 BaseModel
。它提供了核心功能:
- 自动验证字段类型。
- 支持默认值和可选字段。
- 生成 JSON Schema(用于 API 文档)。
基础示例
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
# 使用字典初始化
user_data = {"name": "Alice", "age": 25}
user = User(**user_data) # 自动验证字段类型
print(user.name) # 输出: Alice
print(user.age) # 输出: 25
3. 如何编写自己的 Pydantic 模型?
(1) 定义字段类型
Pydantic 支持 Python 原生类型和复杂类型:
from typing import Optional, List
from datetime import datetime
import uuid
class Product(BaseModel):
id: uuid.UUID # UUID 类型
name: str # 必填字符串
price: float # 浮点数
tags: List[str] # 字符串列表
created_at: datetime # 日期时间
discount: Optional[float] = None # 可选字段
(2) 添加字段约束
使用 Field
定义更复杂的规则:
from pydantic import BaseModel, Field
class User(BaseModel):
username: str = Field(..., min_length=3, max_length=20) # 必填,长度3-20
email: str = Field(..., regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
age: int = Field(ge=18, description="必须成年") # 年龄 ≥ 18
(3) 自定义验证逻辑
通过 @validator
添加自定义验证:
from pydantic import validator
class Payment(BaseModel):
amount: float
currency: str
@validator("amount")
def amount_must_be_positive(cls, v):
if v <= 0:
raise ValueError("金额必须大于0")
return v
@validator("currency")
def currency_must_be_valid(cls, v):
if v not in ["USD", "EUR", "JPY"]:
raise ValueError("无效的货币类型")
return v
(4) 嵌套模型
模型可以嵌套其他模型:
class Address(BaseModel):
city: str
street: str
class Person(BaseModel):
name: str
address: Address # 嵌套模型
# 使用示例
data = {
"name": "Bob",
"address": {"city": "New York", "street": "5th Ave"}
}
person = Person(**data)
4. 高级用法
(1) 配置模型行为
通过 Config
类自定义模型行为:
class ConfigExample(BaseModel):
name: str
class Config:
anystr_strip_whitespace = True # 自动去除字符串两端空格
allow_population_by_field_name = True # 允许用别名初始化
extra = "forbid" # 禁止额外字段
(2) 生成 JSON Schema
Pydantic 自动为模型生成 JSON Schema:
print(User.schema_json(indent=2))
输出:
{
"title": "User",
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 3,
"maxLength": 20
},
"email": {
"type": "string",
"pattern": "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$"
},
"age": {
"type": "integer",
"minimum": 18,
"description": "必须成年"
}
},
"required": ["username", "email", "age"]
}
(3) 与环境变量集成
从环境变量加载配置:
from pydantic import BaseSettings
class Settings(BaseSettings):
api_key: str
debug: bool = False
class Config:
env_file = ".env" # 从.env文件加载
settings = Settings() # 自动读取环境变量
5. 完整示例:用户注册 API 模型
from pydantic import BaseModel, Field, EmailStr, validator
from typing import Optional
from datetime import datetime
class UserRegister(BaseModel):
username: str = Field(..., min_length=3, max_length=20)
email: EmailStr # 专门验证邮箱格式的类型
password: str = Field(..., min_length=8)
birth_date: Optional[datetime] = None
referral_code: Optional[str] = Field(None, max_length=10)
@validator("password")
def password_must_contain_special_char(cls, v):
if not any(c in "!@#$%^&*" for c in v):
raise ValueError("密码必须包含特殊字符")
return v
# 使用示例
user_data = {
"username": "alice123",
"email": "alice@example.com",
"password": "secure!123"
}
user = UserRegister(**user_data) # 自动验证
6. 常见问题解答
Q1:Pydantic 和 Dataclasses 有什么区别?
- Pydantic:专注于数据验证和解析,支持复杂约束(如正则、自定义验证)。
- Dataclasses:仅生成
__init__
和__repr__
,无验证功能。
Q2:如何处理未知字段?
通过 Config
控制:
class Config:
extra = "allow" # 允许额外字段(默认)
extra = "forbid" # 禁止额外字段
extra = "ignore" # 忽略额外字段
Q3:性能如何?
Pydantic 在首次运行时会生成验证逻辑的优化代码,后续调用速度接近原生 Python。
总结
功能 | 实现方式 |
---|---|
基础字段定义 | name: str |
字段约束 | Field(..., min_length=3) |
自定义验证 | @validator 装饰器 |
嵌套模型 | 直接嵌套其他 BaseModel |
环境变量集成 | 继承 BaseSettings + Config |
生成 API 文档 | 自动通过 schema_json() 或 FastAPI 集成 |
通过 Pydantic,你可以用极少的代码实现强大的数据验证和转换逻辑,非常适合 API 开发、配置管理和数据处理场景。