FastAPI 教程详解:用 Pydantic `Field` 为请求体模型声明字段校验与元数据(Body - Fields)
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 中你可以用Query、Path、Body为路径操作函数path operation function的参数声明附加的校验规则与元数据而本篇所介绍的Field则是把同样的能力下放到Pydantic 模型内部的属性model attribute上——让你在请求体的数据结构定义处就近声明每个字段的约束、标题、描述等 JSON Schema 元数据。读完本篇你将掌握Field的正确导入方式、在模型属性上的完整用法、它与Query/Path/Body共享的底层继承关系以及它生成的 OpenAPI/JSON Schema 究竟长什么样。本篇以仓库内韩语文档 docs/ko/docs/tutorial/body-fields.md 为骨架并结合仓库中的 示例代码、单元测试 与 FastAPI 参数类源码 展开。一、先导概念什么时候需要在模型属性上写校验回顾之前几篇教程你会看到两种位置的声明方式在路径操作函数参数上通过Query、Path、Body声明校验与元数据相关主题见 查询参数与字符串校验、路径参数与数值校验在Pydantic 模型请求体的属性上使用 Pydantic 的Field。当你用BaseModel定义一个请求体模型比如Item字段name、description、price、tax本身已经带有类型约束如str、float但若还需要价格必须大于 0描述最长 300 字符这个字段在文档里显示一个特定标题这类声明式约束就要借助Field写在模型内部——这正是本篇的主题。二、导入Field来源是pydantic不是fastapiField是Pydantic提供的函数因此导入时必须直接来自pydanticfrom fastapi import Body, FastAPI from pydantic import BaseModel, Field⚠️警告重要Field不像Query、Path、Body那样从fastapi导入而是直接从pydantic导入。FastAPI 的这类辅助函数Query、Path、Body等本质上是在 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( defaultNone, titleThe description of the item, max_length300 ) price: float Field(gt0, descriptionThe 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(embedTrue)]): 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(embedTrue)): 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(defaultNone, title..., max_length300)默认值为None可选字段文档标题显示为The description of the item长度上限 300priceField(gt0, description...)必须大于 0并附带一段用于交互文档的描述文本name、tax普通类型注解无Field仅类型约束无附加元数据其中gt0对应大于greater than约束FastAPI 会据此生成数值校验max_length300则约束字符串长度。测试 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 schemaGET /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 的映射关系defaultNonestr | None联合类型 →anyOf中包含{type: null}titleThe description of the item→ 属性title直接替换默认标题max_length300→ 出现在字符串 schema 的maxLength键gt0→ 对应数值 schema 的exclusiveMinimum: 0.0description...→ 原样出现在属性description上。也就是说Field中声明的一切都会被纳入JSON Schema并最终进入OpenAPI schema进而在/docs交互式文档与生成客户端中可见。这正是原文档强调用Field声明校验和元数据的核心价值。五、深入原理Field与Query/Path/Body的底层血缘关系原文档用一段技术细节Technical Details说明了它们之间的类层次关系我们可以结合仓库源码来印证fastapi中你看到的Query、Path、Body从fastapi导入时实际上是函数调用后返回特定类的对象这些类Query、Path等是公共类Param的子类而Param本身又是 PydanticFieldInfo的子类Pydantic 的Field返回的同样是FieldInfo的实例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):——Path、Query继承自Param第 469 行class Body(FieldInfo):——Body直接继承FieldInfo。而 fastapi/param_functions.py 则定义了Query()、Path()、Body()等对外暴露的函数用于创建上述类的实例。正是因为有FieldInfo这条共同的血缘Field才能与Query、Path、Body共享同一套参数集合标题、默认值、数值范围、长度约束、描述等。用原文档里的话说模型中的每个属性——类型 默认值 Field——与路径操作函数参数——用Field替换掉Path/Query/Body——在结构上是同构的。这也是为什么 Pydantic 模型可以直接作为 FastAPI 的请求体/响应模型使用两者共享同一套元数据语义。技巧把Field与Query、Body放在一起对比记忆会事半功倍——它们在声明结构、参数名与生成的 Schema 行为上高度一致只是作用对象不同Field面向模型属性其余三者面向路径操作函数的参数。六、传递额外信息自定义键会进入 OpenAPI但要谨慎在Field、Query、Body等中你还可以传入任意额外信息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除了常规约束如gt、max_length、default、title、description还可以通过额外关键字参数向生成的 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),仅供参考