ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

FastAPI 请求体(Request Body)完全指南:用 Pydantic 模型声明与校验 POST/PUT 数据

FastAPI 请求体(Request Body)完全指南:用 Pydantic 模型声明与校验 POST/PUT 数据 FastAPI 请求体Request Body完全指南用 Pydantic 模型声明与校验 POST/PUT 数据【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本指南以 FastAPI 官方教程「请求体Request Body」为核心系统讲解如何用 Pydantic 模型接收客户端如浏览器、移动端提交的 JSON 数据涵盖模型定义、必填/可选字段声明、与路径参数、查询参数的混用规则并结合仓库内 docs_src/body/ 下的示例源码与 tests/test_tutorial/test_body/ 中的测试用例向你展示 FastAPI 如何把「类型声明」变成「JSON 解析 数据校验 OpenAPI 文档」一整条自动化链路。读完本文你将能独立写出健壮的 POST/PUT 接口并精确理解每个参数最终落在请求的哪个位置。什么是请求体何时需要发送当客户端比如浏览器或移动 App需要向你的 API 发送数据时数据通常以请求体request body的形式发送。相应地响应体response body是你的 API 返回给客户端的数据。需要区分的是API 几乎总要返回响应体但客户端并不总是需要发送请求体——有时客户端只是请求某个路径可能带上几个查询参数但不会携带 body。因此FastAPI 教程对请求体的定位是在“确有必要”时才用它来承载结构化数据。关于请求方法官方文档给出了明确提醒要发送数据应使用POST最常见、PUT、DELETE或PATCH之一在GET请求中发送 body在规范HTTP 规范中属于未定义行为。FastAPI 出于对非常复杂/极端场景的兼容性仍然支持它但这是被强烈不鼓励的做法——Swagger UI 交互式文档不会为GET展示 body 文档且中间代理proxy也很可能不支持这种用法。声明请求体的方式十分简单使用 Pydantic 模型——借助 Pydantic 的全部能力与优势来完成类型转换、校验和序列化。第一步导入 Pydantic 的BaseModel在开始前先引入必要的依赖。示例代码位于 docs_src/body/tutorial001_py310.py首先从pydantic导入BaseModelfrom fastapi import FastAPI from pydantic import BaseModel这里的fastapi.FastAPI用于创建应用实例而BaseModel是你定义数据模型的基类。第二步定义数据模型Data Model把数据模型声明为继承自BaseModel的类并使用标准的 Python 类型标注所有属性class Item(BaseModel): name: str description: str | None None price: float tax: float | None None必填与可选字段的约定与声明查询参数时的规则一致模型属性有默认值→ 该字段非必填模型属性没有默认值→ 该字段必填使用None作为默认值即可让字段可选。在上面的Item模型中name: str与price: float没有默认值因此必填description与tax的默认值为None因此是可选的。这个模型对应一个 JSON「对象」即 Python 的dict例如{ name: Foo, description: An optional description, price: 45.2, tax: 3.5 }因为description和tax可选下面的 JSON 同样是合法的请求体{ name: Foo, price: 45.2 }可选项的文本内容但别选错可选语义注意区分两种“可选”用str | NonePython 3.10 联合类型语法只表达“类型上允许为 None”它本身并不决定字段是否必填真正让字段“非必填”的是 None这个默认值。这一点在下文混用查询参数时会再次印证。第三步把模型声明为路径操作函数的参数在路径操作path operation函数里把它当作参数声明即可——就像之前声明路径参数和查询参数那样并把类型标注为你创建的模型Itemapp FastAPI() app.post(/items/) async def create_item(item: Item): return item只靠这一处 Python 类型声明FastAPI 就会自动完成将请求体作为 JSON 读取转换对应的类型如有需要比如把字符串50.5转成float校验数据——若数据非法会返回清晰明确的错误精确指出错误位置与错误内容HTTP 422 与ValidationError结构把接收到的数据放入参数item——由于你在函数中把item的类型声明为Item编辑器会对该参数的全部属性及其类型提供自动补全等支持为模型生成 JSON Schema 定义这些 Schema 可被项目在其他地方复用这些 Schema 会成为生成的OpenAPI Schema的一部分并被自动文档 UI 使用。完整可运行的示例见 docs_src/body/tutorial001_py310.py。源码级佐证请求体在 OpenAPI 中如何呈现仓库中的测试 tests/test_tutorial/test_body/test_tutorial001.py 对生成的/openapi.json做了快照断言test_openapi_schema。从中可以看到POST /items/的 OpenAPI 定义里出现了requestBody: { content: { application/json: { schema: {$ref: #/components/schemas/Item} } }, required: true }同时components.schemas.Item被生成为type: object其中required列表恰好是[name, price]两个无默认值的字段而description与tax被描述为anyOf: [{type: string}, {type: null}]/anyOf: [{type: number}, {type: null}]。这就是“默认值决定必填性、类型标注决定 Schema”最直观的代码证据。校验失败的真实形态来自测试断言同样是上述测试文件覆盖了各种异常请求并断言返回 HTTP 422请求场景结果缺少必填字段如只传{name: Foo}422错误type: missingloc: [body, price]传了无法解析为数字的字符串price: twenty422错误type: float_parsing请求体为空对象{}422同时报告name与price缺失请求体为null422错误定位到loc: [body]JSON 语法损坏422错误type: json_invalid并附ctx.error提交表单而非 JSONapplication/x-www-form-urlencoded422Content-Type不是 JSON 类型422反过来只要Content-Type: application/json或application/geojson等 JSON 变体且数据合法返回就是 200。另外测试还演示了类型强制转换price传字符串50.5时响应中会变成浮点数50.5——这正是“按需转换类型”的直接证据。在函数中使用模型对象进入函数内部后可以直接访问模型对象的各个属性。教程的进阶版示例 docs_src/body/tutorial002_py310.py 展示了更真实的业务用法先把模型转为dict再依据可选字段动态加工数据。app.post(/items/) async def create_item(item: Item): item_dict item.model_dump() if item.tax is not None: price_with_tax item.price item.tax item_dict.update({price_with_tax: price_with_tax}) return item_dict这里的item.model_dump()Pydantic v2 中替代旧版item.dict()的方法把模型实例序列化为普通dict随后检查可选字段item.tax是否真的传入了值只有非None时才计算含税价格并追加键price_with_tax。对应的测试 tests/test_tutorial/test_body/test_tutorial002.py 也很有意思传tax: 0.3时响应为{name: Foo, price: 50.5, description: Some Foo, tax: 0.3, price_with_tax: 50.8}——证明price_with_tax由 50.5 0.3 计算而来不传tax时响应中不含price_with_tax键tax为None——证明model_dump()保留了可选键为None而条件分支正确地跳过了计算测试用参数化同时验证了price传50.5字符串与50.5浮点数时都能得到相同的50.5数值结果再次佐证类型转换能力。请求体与路径参数同时使用你完全可以同时声明路径参数与请求体。FastAPI 会智能识别函数参数中与路径参数同名/匹配的从路径中取值被声明为Pydantic 模型类型的参数则从请求体中读取。来看示例 docs_src/body/tutorial003_py310.pyapp.put(/items/{item_id}) async def update_item(item_id: int, item: Item): return {item_id: item_id, **item.model_dump()}这里item_id出现在路径/items/{item_id}中因此被当作路径参数解析为intitem的类型是 Pydantic 模型于是被当作请求体解析。返回值把路径中的item_id与模型字段合并成一个响应对象。测试 tests/test_tutorial/test_body/test_tutorial003.py 中用client.put(/items/123, json{...})验证路径中的123被转换为整数123响应为{item_id: 123, ...}。同时该测试生成的 OpenAPI 快照中路径参数item_id位于parametersin: path、required: true、type: integer而请求体独立出现在requestBody——这说明二者在文档和解析上完全分离、互不干扰。请求体 路径参数 查询参数三者混用更进一步你还可以在同一个接口里同时声明请求体、路径参数和查询参数FastAPI 会为每个参数自动从正确位置取值。示例见 docs_src/body/tutorial004_py310.pyapp.put(/items/{item_id}) async def update_item(item_id: int, item: Item, q: str | None None): result {item_id: item_id, **item.model_dump()} if q: result.update({q: q}) return result调用/items/123?qsomequery并携带 JSON 请求体时item_id来自路径、q来自查询串、item来自请求体。FastAPI 的参数识别规则函数参数会被按如下规则归类官方文档明确给出若参数同时声明在路径中 → 作为路径参数若参数是单一类型如int、float、str、bool等→ 作为查询参数若参数类型被声明为Pydantic 模型→ 作为请求体。关于q: str | None None的必填性说明文档特别提示FastAPI 判断q非必填依据的是默认值 None而不是str | None这个类型注解本身。不加默认值的q: str就会变成必填查询参数。当然写出str | None这样的类型注解依然有意义——它能让编辑器给出更好的补全与错误提示这属于“类型正确性”的范畴。对应的测试 tests/test_tutorial/test_body/test_tutorial004.py 做了两点关键验证行为上client.put(/items/123, json{...}, params{q: somequery})时响应包含q: somequery不带q时响应不含该键。文档上OpenAPI 快照中q出现在parameters里且为required: false的in: query参数模型Item仍然只在requestBody中被引用。这正好与“默认值None→ 非必填”及“单值类型 → 查询参数”两条规则互相印证。自动生成的交互式文档由于模型会被纳入 OpenAPI Schema自动生成的交互式 API 文档会直接展示你的数据模型例如在「Schemas」区域列出模型的 JSON Schema文档截图见 docs/en/docs/img/tutorial/body/image01.png在每个使用该模型的路径操作内部也会内嵌展示该请求体 Schema 与 422 校验错误结构见 docs/en/docs/img/tutorial/body/image02.png。你可以访问应用根路径的/docsSwagger UI直接试发请求体并观察校验响应。编辑器的类型提示与自动补全支持使用 Pydantic 模型而非裸dict的另一个巨大好处是编辑器支持在函数体内编写item.时编辑器会给出所有属性及其类型的补全与类型提示截图见 docs/en/docs/img/tutorial/body/image03.png对类型不正确的操作例如把item.pricefloat当字符串拼接编辑器会直接标出错误截图见 docs/en/docs/img/tutorial/body/image04.png。这种体验并非巧合FastAPI 整个框架正是围绕“类型声明驱动”这一设计目标构建的并且在实现之前就经过了设计阶段的严格测试以确保能与各家编辑器协同工作Pydantic 本身也为此做过相应改动。上面的截图来自 Visual Studio Code但在 PyCharm 及大多数主流 Python 编辑器中也有一致的体验PyCharm 下的效果见 docs/en/docs/img/tutorial/body/image05.png。若使用 PyCharm还可以安装 Pydantic PyCharm Plugin 来获得对 Pydantic 模型更完善的自动补全、类型检查、重构、搜索与代码检查能力。不使用 Pydantic 的替代方案如果你不想使用 Pydantic 模型也可以直接用Body参数来接收请求体中的单个值。相关内容属于「请求体 – 多参数」教程的范畴详见官方文档 docs/en/docs/tutorial/body-multiple-params.md#singular-values-in-body 中「body 中的单值」一节法语文档入口见 docs/fr/docs/tutorial/body.md 结尾的指引。小结从一次简单的POST /items/到「路径参数 查询参数 请求体」三合一接口FastAPI 请求体的核心心智模型只有一句话类型声明即一切。写对类型、写对默认值FastAPI 就替你完成了 JSON 读取、类型转换、数据校验、422 错误响应与 OpenAPI 文档生成的全部工作而 Pydantic 模型带来的编辑器补全与静态检查则让这类代码从「能跑」走向「可靠、可维护」。想进一步实践可以运行仓库内docs_src/body/下的四个示例并用tests/test_tutorial/test_body/目录中的测试用例对照学习各种边界情况缺字段、坏 JSON、错误 Content-Type、类型强转等。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表