Skip to content

第九章:特殊类型进阶 ​

9.1 枚举 Enum ​

python
from enum import Enum

class Role(str, Enum):          # 继承 str,序列化更友好
    ADMIN = "admin"
    USER = "user"

class Account(BaseModel):
    name: str
    role: Role

Account(name="小明", role="admin")   # 字符串自动匹配枚举值

9.2 Literal:限定只能是某几个值 ​

python
from typing import Literal

class Request(BaseModel):
    method: Literal["GET", "POST", "PUT", "DELETE"]
    sort_order: Literal["asc", "desc"] = "asc"

比枚举更轻量,IDE 还能自动补全可选值。

9.3 Annotated:类型与约束分离(推荐写法) ​

把约束写在类型里而不是 Field() 里,可复用、更现代:

python
from typing import Annotated
from pydantic import BaseModel, Field

# 定义一次,到处使用
ShortStr = Annotated[str, Field(min_length=1, max_length=50)]
PositiveAmount = Annotated[float, Field(gt=0)]

class Product(BaseModel):
    name: ShortStr
    category: ShortStr
    price: PositiveAmount

9.4 自定义类型:Annotated + 校验函数 ​

python
from typing import Annotated
from pydantic import AfterValidator

def must_be_even(v: int) -> int:
    if v % 2 != 0:
        raise ValueError("必须是偶数")
    return v

EvenInt = Annotated[int, AfterValidator(must_be_even)]

class Demo(BaseModel):
    num: EvenInt      # 传 3 会报错,传 4 通过

这是 v2 扩展类型的标准姿势:不写类、不写魔法方法,一个函数搞定。

9.5 Any 与 TypeAdapter ​

实在不想建模时可以用 data: Any(放弃校验)。另外 Pydantic 提供 TypeAdapter,不建模型也能校验任意类型,特别适合一次性的小校验:

python
from pydantic import TypeAdapter

adapter = TypeAdapter(list[int])
adapter.validate_python(["1", "2", 3])   # → [1, 2, 3]
adapter.validate_json('["a"]')           # → 报错

9.6 日期与计算属性 ​

python
from pydantic import BaseModel, computed_field

class Rectangle(BaseModel):
    width: float
    height: float

    @computed_field          # 像属性一样访问,还会出现在 model_dump() 里
    @property
    def area(self) -> float:
        return self.width * self.height