Pydantic v2 零基础入门教程(二)- 复合与特殊数据类型,接口开发核心

文章目录

  • 前言
  • 一、阶段学习目标
  • [二、复合容器类型:list / dict / set](#二、复合容器类型:list / dict / set)
    • [2.1 列表 list 精准校验](#2.1 列表 list 精准校验)
    • [2.2 字典 dict 精准校验](#2.2 字典 dict 精准校验)
      • [2\.3 集合 set 去重校验](#2.3 集合 set 去重校验)
  • 三、重中之重:嵌套模型(企业项目核心)
    • [3.1 单层嵌套模型](#3.1 单层嵌套模型)
    • [3.2 嵌套模型列表(最常用)](#3.2 嵌套模型列表(最常用))
  • 四、官方内置特殊类型(开箱即用,无需手写校验)
    • [4.1 时间类型:datetime / date 自动解析](#4.1 时间类型:datetime / date 自动解析)
    • [4.2 邮箱、网址、IP 专属校验](#4.2 邮箱、网址、IP 专属校验)
  • 五、多类型兼容与枚举约束
    • [5.1 Optional / Union 多类型兼容](#5.1 Optional / Union 多类型兼容)
    • [5.2 Literal 固定枚举值(轻量状态约束)](#5.2 Literal 固定枚举值(轻量状态约束))
    • [5.3 Enum 标准枚举类(企业级规范)](#5.3 Enum 标准枚举类(企业级规范))
  • [六、阶段核心总结(Day2 必背)](#六、阶段核心总结(Day2 必背))
  • 七、新手高频坑点

前言

上一篇我们完成了 Pydantic v2 核心基础 的学习,掌握了 BaseModel、基础字段、Field 约束、异常捕获等底层能力。

但真实业务中,数据从来不是单一的 int/str,绝大多数场景都是:列表、字典、多层嵌套、时间、邮箱、URL、固定枚举值 等复杂结构。

本文为 Pydantic v2 零基础系列·第二阶段 ,一天吃透复合容器类型 + 嵌套模型 + 官方专属特殊类型 + 枚举类型 ,这是 FastAPI 接口开发、数据清洗、配置解析的最高频核心能力

全程纯 v2 语法、无 v1 兼容代码、全部案例可直接复制运行。

一、阶段学习目标

读完本文你将掌握:

  1. list / dict / set 容器类型精准校验

  2. 嵌套模型(企业项目 90% 场景在用)

  3. datetime / date 时间字符串自动解析

  4. Email / URL / IP 等开箱即用特殊类型

  5. Union 多类型兼容、Optional 可选类型

  6. Literal / Enum 固定枚举值(状态、角色场景必备)

二、复合容器类型:list / dict / set

基础类型只能校验单个值,容器类型可以批量校验一组数据,支持强制约束容器内的元素类型,杜绝脏数据。

2.1 列表 list 精准校验

语法:list[元素类型],严格校验每一个元素类型,非法元素直接报错。

python 复制代码
from pydantic import BaseModel, ValidationError

class User(BaseModel):
    # 字符串列表:只能存放字符串
    tags: list[str]
    # 数字列表:只能存放int数字
    scores: list[int]

# 正常数据
try:
    u1 = User(tags=["技术", "Python"], scores=[90, 88, 95])
    print("✅ 正常列表数据:", u1.model_dump())
except ValidationError as e:
    print(e.errors())

# 非法数据:列表包含非字符串、非数字
try:
    User(tags=[123, "Python"], scores=[90, "abc"])
except ValidationError as e:
    print("\n❌ 列表校验失败:")
    for err in e.errors():
        print(f"字段:{err['loc']}  原因:{err['msg']}")

2.2 字典 dict 精准校验

语法:dict[键类型, 值类型],约束字典 key、value 的数据类型。

python 复制代码
from pydantic import BaseModel

class User(BaseModel):
    # 键为字符串,值为浮点数
    subject_score: dict[str, float]

u = User(subject_score={"语文": 92.5, "数学": 96.0})
print("字典解析结果:", u.model_dump())

2.3 集合 set 去重校验

set 会自动去重,同时约束元素类型,适合标签、权限、唯一标识场景。

python 复制代码
from pydantic import BaseModel

class User(BaseModel):
    permissions: set[str]

# 自动去重
u = User(permissions=["read", "write", "read"])
print("集合自动去重:", u.model_dump())

三、重中之重:嵌套模型(企业项目核心)

真实业务数据全部是嵌套结构:用户-地址、订单-商品、文章-评论

Pydantic 支持模型嵌套模型、模型列表嵌套,可以完美映射任意复杂 JSON 结构,也是面试、工作高频考点。

3.1 单层嵌套模型

python 复制代码
from pydantic import BaseModel

# 子模型:地址模型
class Address(BaseModel):
    province: str
    city: str
    detail: str

# 主模型:用户模型,嵌套地址
class User(BaseModel):
    id: int
    name: str
    address: Address  # 嵌套单个模型

# 原始嵌套字典数据
raw_data = {
    "id": 1001,
    "name": "张三",
    "address": {
        "province": "广东省",
        "city": "深圳市",
        "detail": "科技园"
    }
}

user = User.model_validate(raw_data)
print("嵌套模型解析结果:")
print(user.model_dump_json(indent=2))
# 直接点取嵌套字段
print("\n用户城市:", user.address.city)

3.2 嵌套模型列表(最常用)

场景:一个订单包含多个商品、一个用户拥有多个收货地址

python 复制代码
from pydantic import BaseModel

# 商品子模型
class Goods(BaseModel):
    name: str
    price: float
    num: int

# 订单主模型
class Order(BaseModel):
    order_id: str
    # 嵌套多个商品模型列表
    goods_list: list[Goods]

# 模拟订单数据
order_data = {
    "order_id": "ORD20260627",
    "goods_list": [
        {"name": "Python教程", "price": 59.9, "num": 1},
        {"name": "机械键盘", "price": 199.0, "num": 2}
    ]
}

order = Order.model_validate(order_data)
print("订单嵌套列表解析:")
print(order.model_dump_json(indent=2))

核心优势:无需手动遍历解析字典,Pydantic 自动递归校验、逐层解析,嵌套数据出错精准定位字段位置。

四、官方内置特殊类型(开箱即用,无需手写校验)

Pydantic 内置大量业务常用特殊类型,一行代码实现复杂校验,彻底告别正则手写邮箱、URL、IP、时间校验。

4.1 时间类型:datetime / date 自动解析

支持 字符串自动转时间对象,无需手动 strptime,适配绝大多数接口时间格式。

python 复制代码
from datetime import datetime, date
from pydantic import BaseModel

class User(BaseModel):
    create_time: datetime
    birth_day: date

# 传入字符串,自动解析为时间对象
u = User(create_time="2026-06-27 22:00:00", birth_day="2000-01-01")
print("datetime对象:", u.create_time, type(u.create_time))
print("date对象:", u.birth_day, type(u.birth_day))
# 序列化自动转回标准字符串
print("序列化时间:", u.model_dump_json())

4.2 邮箱、网址、IP 专属校验

需要提前安装拓展依赖:pip install 'pydantic[email]'

python 复制代码
from pydantic import BaseModel, EmailStr, HttpUrl, IPvAnyAddress, ValidationError

class User(BaseModel):
    email: EmailStr        # 自动校验邮箱格式
    avatar_url: HttpUrl    # 自动校验合法URL
    ip: IPvAnyAddress      # 自动校验IPv4/IPv6

# 正常数据
try:
    u = User(
        email="test@qq.com",
        avatar_url="https://www.baidu.com/1.png",
        ip="192.168.1.1"
    )
    print("✅ 特殊类型校验通过:", u.model_dump())
except ValidationError as e:
    print(e.errors())

# 非法数据测试
try:
    User(email="错误邮箱", avatar_url="非法链接", ip="999.999.999.999")
except ValidationError as e:
    print("\n❌ 特殊类型校验失败:")
    for err in e.errors():
        print(f"{err['loc']}: {err['msg']}")

五、多类型兼容与枚举约束

5.1 Optional / Union 多类型兼容

v2 推荐使用 | 替代传统 Union,语法更简洁:

  • int | None:等价 Optionalint,可为数字或空

  • str | int:兼容字符串、数字两种类型

python 复制代码
from typing import Optional, Union
from pydantic import BaseModel

class User(BaseModel):
    # 可为int或None
    # age: int | None = None
    age: Optional[int] = None
    # 兼容字符串/数字分数
    # score: str | int
    score: Union[str, int]

u1 = User(age=22, score="99")
u2 = User(age=None, score=100)
print(u1.model_dump(), u2.model_dump())

5.2 Literal 固定枚举值(轻量状态约束)

适用于角色、状态、开关场景,只能传入指定值,传错直接报错。

python 复制代码
from pydantic import BaseModel, Literal, ValidationError

class User(BaseModel):
    # 只能是 admin / user / guest 三选一
    role: Literal["admin", "user", "guest"]
    status: Literal["active", "inactive"]

try:
    u = User(role="admin", status="active")
    print("✅ 枚举校验通过:", u.model_dump())
except ValidationError as e:
    print(e.errors())

# 非法值测试
try:
    User(role="super_admin", status="off")
except ValidationError as e:
    print("\n❌ 枚举校验失败:", e.errors())

5.3 Enum 标准枚举类(企业级规范)

复杂项目推荐 Enum,代码可读性更高、便于统一管理常量状态。

python 复制代码
from enum import Enum
from pydantic import BaseModel

# 定义枚举
class RoleEnum(str, Enum):
    ADMIN = "admin"
    USER = "user"
    GUEST = "guest"

class User(BaseModel):
    role: RoleEnum

u = User(role="admin")
print("枚举解析结果:", u.model_dump())
print("枚举值:", u.role.value)

六、阶段核心总结(Day2 必背)

学完本文必须掌握的 6 大核心能力:

  1. 容器类型:list/dict/set 强约束元素类型,批量校验数据

  2. 嵌套模型:支持无限层级嵌套,完美适配复杂业务JSON

  3. 时间自动解析:字符串一键转 datetime/date 对象

  4. 特殊类型:EmailStr / HttpUrl / IP 开箱即用校验

  5. 多类型兼容类型 | None、多类型 Union 适配灵活字段

  6. 状态枚举:Literal 轻量枚举、Enum 标准枚举,约束固定值

七、新手高频坑点

  • ❌ 嵌套字典不要用 dict 硬接,优先嵌套模型,校验更精准、可读性更强

  • ❌ 时间字段不要手动解析,交给 Pydantic 自动转换

  • ❌ 状态字段不要用普通字符串,优先 Literal/Enum 防脏数据

  • ✅ 列表务必声明元素类型list[str],不要裸写 list