FastAPI 教程详解:用 Pydantic `Field` 为请求体模型声明字段校验与元数据(Body - Fields)
2026/9/9 20:49:18 网站建设 项目流程

FastAPI 教程详解:用 PydanticField为请求体模型声明字段校验与元数据(Body - Fields)

【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi

在 FastAPI 中,你可以用QueryPathBody为路径操作函数(path operation function)的参数声明附加的校验规则与元数据;而本篇所介绍的Field,则是把同样的能力"下放"到Pydantic 模型内部的属性(model attribute)上——让你在请求体的数据结构定义处,就近声明每个字段的约束、标题、描述等 JSON Schema 元数据。读完本篇,你将掌握Field的正确导入方式、在模型属性上的完整用法、它与Query/Path/Body共享的底层继承关系,以及它生成的 OpenAPI/JSON Schema 究竟长什么样。

本篇以仓库内韩语文档 docs/ko/docs/tutorial/body-fields.md 为骨架,并结合仓库中的 示例代码、单元测试 与 FastAPI 参数类源码 展开。

一、先导概念:什么时候需要在模型属性上"写校验"

回顾之前几篇教程你会看到两种位置的声明方式:

  • 路径操作函数参数上:通过QueryPathBody声明校验与元数据,相关主题见 查询参数与字符串校验、路径参数与数值校验;
  • Pydantic 模型(请求体)的属性上:使用 Pydantic 的Field

当你用BaseModel定义一个请求体模型,比如Item,字段namedescriptionpricetax本身已经带有类型约束(如strfloat),但若还需要"价格必须大于 0""描述最长 300 字符""这个字段在文档里显示一个特定标题"这类声明式约束,就要借助Field写在模型内部——这正是本篇的主题。

二、导入Field:来源是pydantic,不是fastapi

FieldPydantic提供的函数,因此导入时必须直接来自pydantic

from fastapi import Body, FastAPI from pydantic import BaseModel, Field

⚠️警告(重要)

Field不像QueryPathBody那样从fastapi导入,而是直接从pydantic导入。FastAPI 的这类辅助函数(QueryPathBody等)本质上是在 FastAPI 层对请求参数的封装,而Field是纯 Pydantic 概念,它服务于模型类的字段声明,不依赖 FastAPI 的请求上下文。这一点在原文档(docs/ko/docs/tutorial/body-fields.md)中被特别强调,混用导入源是新手最容易踩的坑。

仓库内的示例代码 tutorial001_an_py310.py 第 4 行正是这一导入方式的直接体现。

三、在模型属性上声明校验与元数据:完整可运行示例

导入后,就可以在模型类的属性上直接使用Field。仓库中的完整示例(Annotated 风格版本)如下:

from typing import Annotated from fastapi import Body, FastAPI from pydantic import BaseModel, Field app = FastAPI() class Item(BaseModel): name: str description: str | None = Field( default=None, title="The description of the item", max_length=300 ) price: float = Field(gt=0, description="The price must be greater than zero") tax: float | None = None @app.put("/items/{item_id}") async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]): results = {"item_id": item_id, "item": item} return results

对应源码见 docs_src/body_fields/tutorial001_an_py310.py。仓库还提供了不使用Annotated、采用默认值语法的等价版本 docs_src/body_fields/tutorial001_py310.py,二者的差别仅在于请求体参数的声明风格:

@app.put("/items/{item_id}") async def update_item(item_id: int, item: Item = Body(embed=True)): results = {"item_id": item_id, "item": item} return results

两个文件都是py310后缀,表明它们使用了 Python 3.10+ 的X | None联合类型语法;仓库 pyproject.toml 声明requires-python = ">=3.10",对应的测试也都通过needs_py310标记来限定 Python 版本(见 tests/test_tutorial/test_body_fields/test_tutorial001.py)。

这段代码里Field展示了三种用途:

属性声明写法含义
descriptionField(default=None, title=..., max_length=300)默认值为None(可选字段);文档标题显示为"The description of the item";长度上限 300
priceField(gt=0, description=...)必须大于 0;并附带一段用于交互文档的描述文本
nametax普通类型注解(无Field仅类型约束,无附加元数据

其中gt=0对应"大于(greater than)"约束,FastAPI 会据此生成数值校验;max_length=300则约束字符串长度。测试 test_tutorial001.py 验证了当请求中price为负数-3.0时接口返回422,错误类型为greater_thanmsg"Input should be greater than 0"——说明gt校验在运行时真实生效。

四、运行与验证:字段元数据如何落到 JSON Schema / OpenAPI

将上面应用保存后用uvicorn运行(FastAPI 自带fastapi dev/uvicorn工作流),请求PUT /items/5

{"item": {"name": "Foo", "price": 3.0}}

返回中会由 FastAPI 自动补齐默认字段:

{ "item_id": 5, "item": {"name": "Foo", "price": 3.0, "description": null, "tax": null} }

这一点由测试 test_items_5 精确断言。更关键的是观察生成的 OpenAPI schema(GET /openapi.json),测试 test_openapi_schema 给出了快照级的预期结果。其中Item模型对应的components.schemas.Item会呈现:

"Item": { "title": "Item", "required": ["name", "price"], "type": "object", "properties": { "name": {"title": "Name", "type": "string"}, "description": { "title": "The description of the item", "anyOf": [{"maxLength": 300, "type": "string"}, {"type": "null"}] }, "price": { "title": "Price", "exclusiveMinimum": 0.0, "type": "number", "description": "The price must be greater than zero" }, "tax": {"title": "Tax", "anyOf": [{"type": "number"}, {"type": "null"}]} } }

从这份输出可以清晰地读出Field参数与 JSON Schema 的映射关系:

  • default=None+str | None联合类型 →anyOf中包含{"type": "null"}
  • title="The description of the item"→ 属性title直接替换默认标题;
  • max_length=300→ 出现在字符串 schema 的maxLength键;
  • gt=0→ 对应数值 schema 的exclusiveMinimum: 0.0
  • description=...→ 原样出现在属性description上。

也就是说,Field中声明的一切都会被纳入JSON Schema,并最终进入OpenAPI schema,进而在/docs交互式文档与生成客户端中可见。这正是原文档强调"用Field声明校验和元数据"的核心价值。

五、深入原理:FieldQuery/Path/Body的底层血缘关系

原文档用一段"技术细节(Technical Details)"说明了它们之间的类层次关系,我们可以结合仓库源码来印证:

  1. fastapi中你看到的QueryPathBody,从fastapi导入时实际上是函数,调用后返回特定类的对象;
  2. 这些类(QueryPath等)是公共类Param的子类,而Param本身又是 PydanticFieldInfo的子类;
  3. Pydantic 的Field返回的同样是FieldInfo的实例;
  4. Body直接返回FieldInfo子类的对象,后续教程中还会有其他Body子类的存在。

打开仓库源码 fastapi/params.py 可以逐条核对:

  • 第 10 行from pydantic.fields import FieldInfo
  • 第 26 行class Param(FieldInfo):—— 公共参数基类直接继承 Pydantic 的FieldInfo
  • 第 137 行class Path(Param):、第 221 行class Query(Param):——PathQuery继承自Param
  • 第 469 行class Body(FieldInfo):——Body直接继承FieldInfo

而 fastapi/param_functions.py 则定义了Query()Path()Body()等对外暴露的函数,用于创建上述类的实例。

正是因为有FieldInfo这条共同的"血缘",Field才能与QueryPathBody共享同一套参数集合(标题、默认值、数值范围、长度约束、描述等)。用原文档里的话说:模型中的每个属性——类型 + 默认值 +Field——与路径操作函数参数——用Field替换掉Path/Query/Body——在结构上是同构的。这也是为什么 Pydantic 模型可以直接作为 FastAPI 的请求体/响应模型使用:两者共享同一套元数据语义。

💡技巧:把FieldQueryBody放在一起对比记忆会事半功倍——它们在声明结构、参数名与生成的 Schema 行为上高度一致,只是作用对象不同:Field面向模型属性,其余三者面向路径操作函数的参数。

六、传递额外信息:自定义键会进入 OpenAPI,但要谨慎

FieldQueryBody等中,你还可以传入任意"额外信息"(extra information),例如为后续学习"示例(examples)"章节时使用的键。这些内容会被包含进生成的 JSON Schema。

仓库中关于如何在请求体中声明示例的进阶主题位于 Schema 额外示例(schema-extra-example);而本篇示例中直接通过description为字段附加说明文本,就是"额外元数据进入 schema"的最简形式。

⚠️警告

传递给Field的额外键也会出现在你应用的最终 OpenAPI schema 中。由于这些键未必属于 OpenAPI 规范本身,一些严格的 OpenAPI 工具(例如 OpenAPI 官方校验器 swagger validator)可能无法兼容你生成的 schema。因此,自定义额外键要节制使用,并清楚其只在部分工具链内可见。

七、小结(Recap)

  • 使用 Pydantic 的Field,可以在模型属性层面声明附加校验与元数据,与Query/Path/Body在路径操作函数参数层面提供的能力一一对应;
  • Field必须从pydantic导入(而非fastapi);
  • 除了常规约束(如gtmax_lengthdefaulttitledescription),还可以通过额外关键字参数向生成的 JSON Schema / OpenAPI 传递自定义元数据;
  • 模型的完整示例代码与测试分别位于 docs_src/body_fields/ 与 tests/test_tutorial/test_body_fields/test_tutorial001.py,可作为对照学习的可运行范本。

掌握Field后,建议继续阅读仓库中的相关主题以形成完整拼图:嵌套模型的字段声明见 Body - Nested Models,请求体与参数混用见 Body - Multiple Params。若需对照其他语言版本,本教程的英文原文位于 docs/en/docs/tutorial/body-fields.md。

【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询