Skip to content

第六章:嵌套模型与复杂结构 ​

真实数据几乎都不是扁平的。Pydantic 的嵌套能力是它最实用的部分。

6.1 模型套模型 ​

python
class Address(BaseModel):
    city: str
    street: str
    zipcode: str = Field(pattern=r"^\d{6}$")

class User(BaseModel):
    name: str
    address: Address          # 嵌套模型
    friends: list[Address] = []  # 嵌套模型列表

data = {
    "name": "小明",
    "address": {"city": "北京", "street": "长安街", "zipcode": "100000"},
    "friends": [{"city": "上海", "street": "南京路", "zipcode": "200000"}],
}
user = User.model_validate(data)
print(user.address.city)        # 北京 —— 可以用点号一路访问

嵌套模型的校验也是递归的,错误信息会带上完整路径:friends.0.zipcode,告诉你"friends 列表第 0 个元素的 zipcode 字段错了"。

6.2 自引用模型 ​

树形结构(评论、分类、组织架构)很常见:

python
from __future__ import annotations

class Comment(BaseModel):
    content: str
    replies: list[Comment] = []     # 引用自己

Comment.model_rebuild()             # 解析前向引用(某些场景需要手动调用)

6.3 联合类型:一个字段,多种可能 ​

python
class Cat(BaseModel):
    pet_type: str = "cat"
    meow_volume: int

class Dog(BaseModel):
    pet_type: str = "dog"
    bark_volume: int

class Owner(BaseModel):
    pet: Cat | Dog                  # 联合类型

⚠️ 默认的"智能模式"下,Pydantic 会尝试每个类型取最匹配的一个,有时结果出乎意料。更稳妥的做法是判别联合(Discriminated Union)——用一个字段明确区分类型:

python
from typing import Literal
from pydantic import Field

class Cat(BaseModel):
    pet_type: Literal["cat"] = "cat"    # 判别字段
    meow_volume: int

class Dog(BaseModel):
    pet_type: Literal["dog"] = "dog"
    bark_volume: int

class Owner(BaseModel):
    pet: Cat | Dog = Field(discriminator="pet_type")   # 更快、更准、报错更清晰