文章目录
- 前言
- 一、阶段学习目标
- [二、复合容器类型: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 兼容代码、全部案例可直接复制运行。
一、阶段学习目标
读完本文你将掌握:
-
list / dict / set 容器类型精准校验
-
嵌套模型(企业项目 90% 场景在用)
-
datetime / date 时间字符串自动解析
-
Email / URL / IP 等开箱即用特殊类型
-
Union 多类型兼容、Optional 可选类型
-
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 大核心能力:
-
容器类型:list/dict/set 强约束元素类型,批量校验数据
-
嵌套模型:支持无限层级嵌套,完美适配复杂业务JSON
-
时间自动解析:字符串一键转 datetime/date 对象
-
特殊类型:EmailStr / HttpUrl / IP 开箱即用校验
-
多类型兼容 :
类型 | None、多类型 Union 适配灵活字段 -
状态枚举:Literal 轻量枚举、Enum 标准枚举,约束固定值
七、新手高频坑点
-
❌ 嵌套字典不要用 dict 硬接,优先嵌套模型,校验更精准、可读性更强
-
❌ 时间字段不要手动解析,交给 Pydantic 自动转换
-
❌ 状态字段不要用普通字符串,优先 Literal/Enum 防脏数据
-
✅ 列表务必声明元素类型
list[str],不要裸写 list