pydantic之Field使用教程

下面提供一个针对 Pydantic 中 Field 的通俗易懂、又较为全面的中文教程,适合初学者(“小白”)理解和上手。内容包括 Field 的作用、常用参数、在模型验证和文档生成中的意义,以及丰富的示例与注意事项。


一、什么是 Pydantic 和 Field

  • Pydantic 是一个用于数据校验和设置的 Python 库,常用于 FastAPI、数据处理脚本等场景。它通过 Python 类型注解(type hints)来定义数据模型,并在实例化时自动校验和转换输入数据。
  • Field 是 Pydantic 提供的一个函数/标记,用于在模型属性(字段)上指定更丰富的元信息和校验约束。例如:默认值、校验范围、描述文档、示例、别名等。

简单来说,Field 就像给模型字段“贴标签”,告诉 Pydantic 该字段应如何校验、如何在 OpenAPI 文档中展示、默认值是多少等。


二、Field 的基本用法

2.1 导入与基本语法

from pydantic import BaseModel, Field

class User(BaseModel):
    username: str = Field(...)  # “...” 表示必须提供该字段
    age: int = Field(default=0)  # 如果不提供,默认为 0
  • Field(...) 中通常第一个参数是 default 或 default_factory:

    • Field(default_value):若用户未提供该字段,则使用 default_value
    • Field(...)... 表示“这个字段必填”(no default),如果创建模型时未提供会报错。
    • Field(default_factory=callable):通过可调用对象生成默认值,如 Field(default_factory=list) 表示默认 [],每次新实例化时调用一次函数以免所有实例共用同一个可变默认。

2.2 最简单示例

class Item(BaseModel):
    name: str = Field(..., title="名称", description="项目名称,必填")
    price: float = Field(0.0, gt=0, description="价格,必须大于0")
  • name:使用 Field(..., title="名称", description="项目名称,必填") 强调必填,并添加标题和描述,方便自动生成文档。
  • price:默认值为 0.0,同时用 gt=0 约束大于 0;若输入为负数或 0,会报校验错误。

三、Field 常用参数详解

以下列出 Field(...) 中常见的参数及其作用,便于理解和记忆。格式:Field(default, 参数名=值, ...)

  1. default / default_factory

    • default:字段默认值,如 Field(5)Field("abc")Field(None)
    • default_factory:可调用,用于生成默认值,如 Field(default_factory=list)Field(default_factory=lambda: datetime.utcnow())
    • 注意:default 和 default_factory 不能同时使用。
  2. 校验约束(numeric、string、序列等)

    • 数值类型:gtgeltle

      • gt: “greater than”,严格大于;ge: “greater or equal”,大于等于;同理 lt, le
      • 示例:age: int = Field(..., ge=0, lt=150) 表示年龄在 [0,150) 之间。
    • 字符串长度:min_lengthmax_length

      • 仅对字符串类型有效:name: str = Field(..., min_length=1, max_length=50)
    • 正则表达式:regex

      • phone: str = Field(..., regex=r"^\d{10,11}$"),确保字符串满足正则。
    • 列表/集合类型长度:min_itemsmax_items

      • 对序列类型生效:tags: List[str] = Field(default_factory=list, min_items=1, max_items=5)
    • 数组元素校验:可配合 Pydantic 泛型和子模型使用,Field 本身不对元素类型做深度校验,但 Pydantic 会结合类型注解校验每个元素类型。

  3. 文档和元信息

    • title:字段标题,在自动生成文档(如 OpenAPI/Swagger)中显示为该字段的标题。

    • description:字段描述,自动文档中显示详细说明。

    • exampleexamples:在 Pydantic V1 中,schema_extra 用于示例;在 FastAPI 自动文档中,可在路由中定义 example。Field 也支持 example(Pydantic V2 支持),或通过 schema_extra 全局添加。

    • alias:字段别名,表示 JSON 输入/输出时使用的键名。例如:

      class User(BaseModel):
          full_name: str = Field(..., alias="fullName")
      
      • 创建时可用 { "fullName": "张三" },但访问属性时为 user.full_name
      • 设置 Configallow_population_by_field_name = True 可以同时支持通过属性名赋值。
    • const(仅 Pydantic V2):表示字段值必须恒定(与 default 一致),类似常量。

    • deprecated: 标记字段已过时(在自动文档里提示废弃)。

    • multiple_of: 对数值类型,要求可被某个数整除。

    • strict: 是否开启严格模式(例如类型强转限制更严),Pydantic V1 / V2 具体差异需参考对应版本文档。

  4. 校验顺序细节

    • Pydantic 会先按照类型注解对传入值做类型转换(如 "123" 转为 int 123),然后再检查 Field 中的约束(如 geregex 等)。如果类型转换失败或约束检查失败,就抛出 ValidationError。
    • 对可选类型(Optional[...]Union[..., None])允许 None,但若 Field 加了 min_length 等检查,在值为 None 时会跳过对应检查或报错,视具体情况而定。建议 Optional 字段不要加不适用的约束。
  5. 示例:多个约束组合

from typing import List, Optional
from pydantic import BaseModel, Field

class Product(BaseModel):
    id: int = Field(..., gt=0, description="商品 ID,必须正整数")
    name: str = Field(..., min_length=1, max_length=100, description="商品名称,1-100 字符")
    price: float = Field(..., ge=0.0, description="价格,不可为负")
    tags: List[str] = Field(default_factory=list, min_items=0, max_items=10, description="标签列表,最多 10 项")
    description: Optional[str] = Field(None, max_length=500, description="商品描述,最多 500 字")

四、用于 FastAPI 自动文档

在 FastAPI 中使用 Pydantic 模型作为请求体或响应模型时,Field 提供的 titledescriptionexamplealias 等元信息会自动体现在 Swagger UI 或 Redoc 中,让前后端协作更流畅。

示例:

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class Item(BaseModel):
    name: str = Field(..., title="名称", description="商品名称", example="苹果")
    price: float = Field(..., gt=0, description="价格,必须大于 0", example=9.9)

@app.post("/items", response_model=Item)
def create_item(item: Item):
    # item.name, item.price 都已校验通过
    return item
  • 在 Swagger UI 的请求体示例中,会显示字段名称、示例值、描述等,帮助前端理解如何调用接口。
  • 如果使用 alias,在文档中也会展示别名,注意需在模型 Config 中设置 allow_population_by_field_name 以兼容。

五、Field 与 Config 结合使用

Pydantic 模型还支持 Config 内部类来配置更多全局行为。常见与 Field 结合的配置:

  1. orm_mode = True

    • 当返回数据库 ORM 对象(如 SQLAlchemy model)时,可直接通过 Pydantic 模型序列化。Field 中的约束仍生效。

    • 示例:

      class UserOut(BaseModel):
          id: int
          username: str
          class Config:
              orm_mode = True
      
    • FastAPI 会自动用 Pydantic 将 ORM 返回的对象转换为 dict,再由 ORJSONResponse 等序列化发送。

  2. allow_population_by_field_name = True

    • 如果你在 Field 中使用 alias,此配置允许在初始化模型时使用字段名赋值。

      class User(BaseModel):
          full_name: str = Field(..., alias="fullName")
          class Config:
              allow_population_by_field_name = True
      
      user = User(fullName="张三")
      user2 = User(full_name="李四")  # 也可这样
      
    • 在 FastAPI 请求场景中,一般前端传递 JSON 用 alias 即可;若需要在 Python 代码中以属性名创建实例,可启用此选项。

  3. use_enum_values = True

    • 如果字段是枚举类型(Enum),可以让 Pydantic 在序列化时使用枚举的值而非名称。常与 Field 一起使用枚举字段。

      from enum import Enum
      
      class Role(str, Enum):
          admin = "admin"
          user = "user"
      
      class User(BaseModel):
          username: str
          role: Role = Field(default=Role.user, description="角色")
          class Config:
              use_enum_values = True
      
  4. validate_assignment = True

    • 允许在模型实例属性赋值时重新校验。若你希望对运行时修改字段做校验,可开启此项。

      class Person(BaseModel):
          age: int = Field(..., ge=0)
          class Config:
              validate_assignment = True
      
      p = Person(age=10)
      p.age = -5  # 立即抛 ValidationError
      
  5. Pydantic V2 中的更多配置

    • 如果使用 Pydantic V2,Field 参数与 Config 选项可能有更新,建议查看官方文档。但大多数概念相通:Field 用于字段级别元信息和校验,Config 用于模型级全局行为。

六、默认值与 default_factory 深度说明

  • default:若字段常量或不依赖运行时数据,用 Field("abc")Field(123)

  • default_factory:当默认值需要在运行时生成、或是可变对象(列表、字典)时,用 default_factory,避免多个实例共用同一可变对象。例如:

    class Data(BaseModel):
        items: list[int] = Field(default_factory=list)
    
  • 注意:不要把可变默认写在直接赋值上,如 items: list[int] = [],Pydantic 可能会将同一个列表在多个实例间共享,引发意外。改用 default_factory=list

  • 使用场景:当默认值需根据当前时间动态生成时,可以:

    from datetime import datetime
    class Event(BaseModel):
        created_at: datetime = Field(default_factory=datetime.utcnow)
    

七、高级示例:嵌套模型与 Field

当模型中嵌套其他 Pydantic 模型时,Field 也可为嵌套模型字段提供默认值或元信息:

class Address(BaseModel):
    city: str = Field(..., description="城市")
    zip_code: str = Field(..., regex=r"^\d{5}$", description="邮政编码5位数字")

class User(BaseModel):
    username: str = Field(..., min_length=1)
    address: Address = Field(..., description="用户地址信息")
  • 如果需要默认嵌套值,可用 default_factory

    class User(BaseModel):
        username: str = Field(...)
        address: Address = Field(default_factory=lambda: Address(city="未知", zip_code="00000"))
    
  • 嵌套校验:Pydantic 会递归校验嵌套模型,每个字段的 Field 约束都会生效。


八、Field 在 Schema/JSON Schema 生成中的作用

  • Pydantic 模型可以生成 JSON Schema,用于文档、前端校验等。Field 中的元信息会映射到 JSON Schema:

    • title"title"
    • description"description"
    • default"default"
    • example"example"
    • gt, le 等数值约束 → "minimumExclusive", "maximumInclusive" 等(具体名称依据 JSON Schema 版本)
    • regex"pattern"
  • FastAPI 利用 Pydantic 的 JSON Schema 生成 OpenAPI 文档,Field 中填的描述和示例都会显示在 Swagger UI 中,帮助前端更好理解接口。

可通过以下方式查看生成的 Schema:

from pydantic import BaseModel, Field

class User(BaseModel):
    username: str = Field(..., title="用户名", min_length=1, max_length=32)
    age: int = Field(0, ge=0, le=150)

# 查看 JSON Schema
print(User.schema_json(indent=2, ensure_ascii=False))

结果中会看到 "title": "用户名", "minLength": 1, "maximum": 150 等信息。


九、错误与调试

  1. ValidationError 信息

    • 当实例化模型时,如果输入不符合 Field 约束,Pydantic 会抛出 ValidationError,并给出详细错误位置和类型。例如:

      try:
          User(username="", age=-5)
      except ValidationError as e:
          print(e.json())
      
    • 错误信息会指出哪个字段、哪种校验失败(如 ensure this value has at least 1 charactersvalue is not greater than 0 等),帮助快速定位问题。

  2. 调试 Field 约束

    • 如果某个约束似乎无效,首先确认字段类型注解是否正确,如 age: int 才会应用 gt, ge;如果是 Optional[int],需要注意 None 行为。
    • 确认是否在模型 Config 中有影响验证行为的设置(如 validate_assignment, arbitrary_types_allowed 等)。
    • 对于复杂正则,请在单独环境测试正则再放到 Field 中。
  3. 兼容 Pydantic V1 vs V2

    • 不同版本 Field 参数可能略有差异,若项目升级 Pydantic,需参考对应版本文档。大多数常用参数(gt, ge, min_length 等)在两版中类似。

十、实战小结

  1. 为什么要用 Field

    • 校验约束:通过 Field 指定范围、长度、正则等,自动校验输入数据,保证数据质量。
    • 自动文档:在 FastAPI 等框架中,Field 的 titledescriptionexample 会自动体现在 Swagger UI 上,极大提高前后端沟通效率。
    • 默认值与动态默认:用 default 和 default_factory 管理默认值,避免可变默认陷阱。
    • 别名与序列化定制:通过 alias 控制 JSON 键名,使内部属性和外部接口字段解耦;配合 Config,可双向赋值。
    • Schema 生成:Field 元信息会体现在生成的 JSON Schema 中,可用于前端校验、文档生成、客户端生成代码等。
  2. 如何学习和验证

    • 多写小示例,在 REPL 或脚本中实例化模型,观察校验行为;打印 Model.schema_json() 查看生成 Schema。
    • 在 FastAPI 项目中试用 Field 的各种参数,打开 /docs 看效果;结合 Postman/Swagger 测试边界情况。
    • 阅读官方文档:Pydantic Field 章节(确认 Pydantic 版本),理解 JSON Schema 映射规则。
  3. 常见注意事项

    • 可变默认使用 default_factory;避免把业务逻辑放在 Field,Field 只做数据定义和校验,不适合写额外复杂逻辑。
    • 校验与业务分离:Field 负责基础类型和简单约束(范围、长度、格式);更复杂的业务校验(如唯一性检查、跨字段关联校验)可在代码中或 Pydantic 的 @root_validator/自定义验证函数中实现。
    • 配合 Config 做更高级用法:如 ORM 模式、别名、严格模式、验证赋值等。

附:一个综合示例

from typing import List, Optional
from datetime import datetime
from enum import Enum
from pydantic import BaseModel, Field, root_validator, ValidationError

class Role(str, Enum):
    admin = "admin"
    user = "user"
    guest = "guest"

class Address(BaseModel):
    city: str = Field(..., description="城市名", min_length=1)
    zip_code: str = Field(..., regex=r"^\d{5}$", description="5 位邮编")

class UserIn(BaseModel):
    username: str = Field(..., min_length=3, max_length=32, description="用户名,3-32 字符")
    password: str = Field(..., min_length=6, description="密码,至少6位")
    age: Optional[int] = Field(None, ge=0, le=120, description="年龄,可选,0-120")
    roles: List[Role] = Field(default_factory=lambda: [Role.user], description="用户角色列表")
    address: Optional[Address] = Field(None, description="地址信息")
    created_at: datetime = Field(default_factory=datetime.utcnow, description="创建时间")
    bio: Optional[str] = Field(None, max_length=200, description="个人简介,不超过200字符")

    @root_validator
    def check_age_for_role(cls, values):
        age = values.get("age")
        roles = values.get("roles", [])
        # 假设逻辑:如果未满18岁,不允许 admin 角色
        if age is not None and age < 18 and Role.admin in roles:
            raise ValueError("未满18岁用户不能拥有 admin 角色")
        return values

    class Config:
        orm_mode = True
        allow_population_by_field_name = True

# 测试
try:
    u = UserIn(
        username="张三",
        password="secret123",
        age=16,
        roles=["user", "admin"],  # 触发 root_validator 报错
        address={"city": "北京", "zip_code": "10001"}
    )
except ValidationError as e:
    print("校验错误:", e)

# 查看 schema
print(UserIn.schema_json(indent=2, ensure_ascii=False))
  • 通过 Field 指定了多种约束、默认值、描述等;嵌套 Address 模型也带 Field 校验;使用 Enum 角色;root_validator 做跨字段校验;Config 开启 ORM 模式和别名赋值支持;最后生成 JSON Schema 可用于文档或前端校验。

以上即 Pydantic Field 的全面教程,从基本语法到常用参数、FastAPI 文档支持、Config 结合、高级示例、注意事项等,覆盖了初学者需要了解的大部分内容。建议在实际项目中多练习,打开 Swagger 文档观察效果,逐步加深理解。祝你学习顺利!

posted @ 2025-06-18 16:03  chron  阅读(733)  评论(0)    收藏  举报