> 技术文档 > 【Pydantic】Python 数据验证入门

【Pydantic】Python 数据验证入门


Pydantic

  • 1. 什么是 Pydantic?
  • 2. 安装
  • 3. 基础使用
  • 4. 常用验证规则
    • 4.1 基础验证规则
    • 4.2 列表验证
    • 4.3 自定义验证器
    • 4.4 条件验证
    • 4.5 常用验证类型
  • 5. 实际应用示例
    • 5.1 API 请求验证
    • 5.2 配置管理
  • 6. 小技巧
    • 6.1. 数据转换:
    • 6.2 错误处理:

1. 什么是 Pydantic?

Pydantic 是一个功能强大的 Python 数据验证库,它通过 Python 类型注解实现快速的数据验证和转换。它不仅提供了全面的类型验证、自动数据转换和详细的错误处理机制,还具有基于 Rust 实现的高性能核心验证器。凭借其优秀的 IDE 支持和可扩展性,Pydantic 在 FastAPI 等 Web 框架、配置管理、数据序列化以及 API 接口模型定义等多个场景中得到广泛应用。

2. 安装

pip install pydanticpip install pydantic-settings

3. 基础使用

在开始使用 Pydantic 之前,我们需要了解它的核心概念和基本用法。Pydantic 的核心是通过定义模型类来实现数据验证,这些模型类继承自 BaseModel。

3.1 创建基础模型

基础模型是 Pydantic 中最常用的功能。通过继承 BaseModel 类,我们可以定义数据结构和类型约束。每个字段都可以使用 Python 的类型注解来指定其类型,这些类型会在数据验证时被强制执行。

from pydantic import BaseModelfrom typing import Optionalfrom datetime import datetimeclass 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 - 带默认值的日期时间字段

3.2 数据验证

Pydantic 的数据验证是自动进行的,当创建模型实例时,输入数据会自动根据定义的类型进行验证和转换。如果验证失败,Pydantic 会抛出详细的 ValidationError 异常。

from pydantic import BaseModel, EmailStr, ValidationErrorclass UserRegistration(BaseModel): username: str email: EmailStr age: inttry: # 尝试创建无效数据 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\']}\")

当验证失败时,错误信息会包含:

• 具体是哪个字段验证失败
• 失败的原因
• 期望的数据类型
• 实际接收到的数据类型

3.3 嵌套模型

在实际应用中,数据结构往往是嵌套的。Pydantic 完全支持模型嵌套,这使得我们可以构建复杂的数据结构,同时保持数据验证的严谨性。

from typing import Listclass Address(BaseModel): street: str city: str country: strclass 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\"} ])

嵌套模型的优势:

• 保持数据结构的层次清晰
• 支持复杂的数据验证逻辑
• 方便数据的序列化和反序列化

4. 常用验证规则

Pydantic 提供了丰富的验证规则,可以满足各种复杂的数据验证需求。这些规则可以组合使用,构建出强大的验证逻辑。

4.1 基础验证规则

Field 类是 Pydantic 提供的字段定义工具,它允许我们为字段添加各种验证规则和元数据。通过 Field,我们可以定义字段的约束条件、默认值和描述信息。

from pydantic import BaseModel, Field, EmailStr, HttpUrl, constrclass 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: 大于/小于

4.2 列表验证

from typing import Listclass 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)

4.3 自定义验证器

from pydantic import BaseModel, model_validator, field_validatorfrom datetime import datetimeclass 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

4.4 条件验证

from typing import Optionalfrom pydantic import BaseModel, Field, model_validatorclass 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

4.5 常用验证类型

from pydantic import BaseModel, Field, EmailStr, HttpUrl, conint, confloat, constrclass 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

这些验证规则涵盖了日常开发中最常见的数据验证场景。通过组合使用这些规则,可以构建出复杂的数据验证逻辑。记住几个要点:

  1. Field(…) 中的 … 表示该字段必填
  2. 使用 Optional 或 | None 表示可选字段
  3. 验证器分为字段级 (field_validator) 和模型级 (model_validator)
  4. 可以组合多个验证规则
  5. 验证规则的顺序: 先定义字段,再添加验证规则
  6. 验证规则的执行顺序: 先定义的规则先执行

5. 实际应用示例

5.1 API 请求验证

from fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI()class Item(BaseModel): name: str price: float is_offer: bool = False@app.post(\"/items/\")async def create_item(item: Item): return item

5.2 配置管理

from pydantic_settings import BaseSettings, SettingsConfigDictclass Settings(BaseSettings): database_url: str api_key: str debug: bool = False model_config = SettingsConfigDict(env_file=\'.env\')# 从环境变量加载配置settings = Settings()

6. 小技巧

6.1. 数据转换:

# 字典转模型data = {\"name\": \"John\", \"age\": \"25\"} # 注意 age 是字符串user = User.model_validate(data) # 推荐使用 model_validate 而不是 parse_obj# 模型转 JSONjson_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)

6.2 错误处理:

try: user = User(name=\"John\", age=\"invalid\")except ValidationError as e: print(\"数据无效:\", e)