FastAPI 多 Body 参数详解:混合 Path/Query/Body、Body() 函数与 embed 嵌入机制 📅 发布时间:2026/9/7 8:49:12 👁 浏览次数: FastAPI 多 Body 参数详解混合 Path/Query/Body、Body() 函数与 embed 嵌入机制【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本篇基于 FastAPI 官方教程文档Body – Mehrere Parameterdocs/de/docs/tutorial/body-multiple-params.md展开讲解当请求体不再只有一个 Pydantic 模型时的进阶用法如何自由混合Path、Query与 Body 参数、如何声明多个 Body 参数、如何用Body把单个值收进请求体、以及用embedTrue让单个 Body 参数也按键包裹的方式接收。读完本文你可以掌握组合式请求体的完整声明方式并从源码层面理解 FastAPI 判断何时自动嵌入的底层逻辑。混用 Path、Query 与 Body 参数在已经掌握Path与Query的基础上FastAPI 允许你在同一个路径操作函数中自由混合Path、Query与请求体Body参数声明框架会自动判断每个参数的数据来源。并且 Body 参数也可以设为可选——只需把默认值设为Nonefrom typing import Annotated from fastapi import FastAPI, Path from pydantic import BaseModel app FastAPI() class Item(BaseModel): name: str description: str | None None price: float tax: float | None None app.put(/items/{item_id}) async def update_item( item_id: Annotated[int, Path(titleThe ID of the item to get, ge0, le1000)], q: str | None None, item: Item | None None, ): results {item_id: item_id} if q: results.update({q: q}) if item: results.update({item: item}) return results对应仓库示例文件tutorial001_an_py310.py。要点说明item_id: Annotated[int, Path(...)]从 URL 路径取值并可附加ge0, le1000之类的数值约束与title元数据q: str | None None是单个值参数FastAPI 默认将其解释为Query 参数即?q...不要求显式写Query(...)item: Item | None None是 Pydantic 模型参数FastAPI 将其识别为Body 参数。注意此处的关键细节由于Item | None的默认值是None这个 Body 参数是可选的——请求可以不带请求体。注意在这种情况下来自 Body 的item是可选的因为它以None作为默认值。多个 Body 参数自动以参数名为键嵌入在上述示例中路径操作期望一个包含Item各字段的 JSON 请求体例如{ name: Foo, description: The pretender, price: 42.0, tax: 3.2 }但当你需要同时接收多个模型例如物品和操作用户时可以声明多个 Body 参数from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class Item(BaseModel): name: str description: str | None None price: float tax: float | None None class User(BaseModel): username: str full_name: str | None None app.put(/items/{item_id}) async def update_item(item_id: int, item: Item, user: User): results {item_id: item_id, item: item, user: user} return results对应仓库示例文件tutorial002_py310.py。此时 FastAPI 会检测到函数中不止一个 Body 参数两个 Pydantic 模型参数于是**以参数名作为键字段名**来组织请求体期望的 Body 变为{ item: { name: Foo, description: The pretender, price: 42.0, tax: 3.2 }, user: { username: dave, full_name: Dave Grohl } }注意尽管item的声明方式与之前相同但现在它被期望位于 Body 中item这个键之下。FastAPI 会自动完成请求数据的转换——item参数得到它专属的嵌套内容user参数同理并对这份组合数据进行校验同时将其记录进 OpenAPI Schema 与自动生成的文档中。源码与测试佐证组合 Schema 的生成与校验位置从源码结构看多个 Body 参数自动嵌入的判定发生在依赖解析阶段。fastapi/dependencies/utils.py 中的_should_embed_body_fields()函数给出了明确规则def _should_embed_body_fields(fields: list[ModelField]) - bool: if not fields: return False # More than one dependency could have the same field, it would show up as multiple # fields but its the same one, so count them by name body_param_names_set {field.name for field in fields} # A top level field has to be a single field, not multiple if len(body_param_names_set) 1: return True first_field fields[0] # If it explicitly specifies it is embedded, it has to be embedded if getattr(first_field.field_info, embed, None): return True ...规则可以归纳为Body 参数名超过一个→ 必须嵌入自动按键包裹任一参数显式设置了embedTrue→ 必须嵌入Form/File字段若不是BaseModel或其联合也需嵌入以便提取键值对。真正的取值与校验在 request_body_to_args() 中完成当single_not_embedded_field只有一个 Body 字段且未嵌入成立时整个请求体直接作为该字段的值进行校验否则逐个字段执行body_to_process.get(get_validation_alias(field))即按键名从 Body 字典中提取再对每个字段独立做 Pydantic 校验——这解释了为什么多 Body 参数时每个参数各自嵌套在顶层键下。仓库测试 test_tutorial002.py 完整验证了上述行为test_post_all发送{item: {...}, user: {...}}返回 200缺失字段description、full_name自动补Nonetest_post_no_body/test_post_no_item/test_post_no_user缺少任一键即返回 422且loc精确到[body, item]或[body, user]便于定位错误来源test_post_missing_required_field_in_item嵌套字段缺失时loc会细化到[body, item, price]test_openapi_schema快照断言 OpenAPI Schema 中会自动生成一个组合请求体 SchemaBody_update_item_items__item_id__put其properties为item与user两个$ref且required: [item, user]——证明组合结构会被如实写入文档前端可直接据此调用。单个值收进 BodyBody()的用途与用于 Query 和 Path 参数的Query、Path相对应FastAPI 提供Body来为 Body 参数声明额外信息。例如在上面的双模型基础上你还想在同一个 Body中多加一个importance键from typing import Annotated from fastapi import Body, FastAPI from pydantic import BaseModel app FastAPI() class Item(BaseModel): name: str description: str | None None price: float tax: float | None None class User(BaseModel): username: str full_name: str | None None app.put(/items/{item_id}) async def update_item( item_id: int, item: Item, user: User, importance: Annotated[int, Body()] ): results {item_id: item_id, item: item, user: user, importance: importance} return results对应仓库示例文件tutorial003_an_py310.py。如果直接写importance: int而不加Body()FastAPI 会把它当作Query 参数因为它是单个值。使用Annotated[int, Body()]后它被识别为 Body 中的另一个键期望的请求体为{ item: { name: Foo, description: The pretender, price: 42.0, tax: 3.2 }, user: { username: dave, full_name: Dave Grohl }, importance: 5 }数据类型转换、校验、文档生成等行为与模型参数一致。多个 Body 参数与 Query 参数并存Body 参数与 Query 参数可以任意组合。由于单个值参数默认就是 Query 参数你甚至不需要显式写Query(...)直接q: str | None None即可from typing import Annotated from fastapi import Body, FastAPI from pydantic import BaseModel app FastAPI() class Item(BaseModel): name: str description: str | None None price: float tax: float | None None class User(BaseModel): username: str full_name: str | None None app.put(/items/{item_id}) async def update_item( *, item_id: int, item: Item, user: User, importance: Annotated[int, Body(gt0)], q: str | None None, ): results {item_id: item_id, item: item, user: user, importance: importance} if q: results.update({q: q}) return results对应仓库示例文件tutorial004_an_py310.py。这个例子还顺带展示了两个细节Body(gt0)Body与Query、Path一样支持相同的附加校验与元数据参数。这里gt0表示importance必须大于 0非法值会触发 422 校验错误参数列表开头的*强制后续参数必须按关键字传入避免位置参数误配——这在参数较多时是良好的防御性写法。嵌入单个 Body 参数embedTrue假设你只声明了一个itemBody 参数类型为 Pydantic 模型Item。默认情况下FastAPI 期望请求体直接就是模型内容。但若你希望它像多参数场景那样在item键下接收模型内容可以设置Body的embed参数item: Annotated[Item, Body(embedTrue)]完整示例from typing import Annotated from fastapi import Body, FastAPI from pydantic import BaseModel app FastAPI() class Item(BaseModel): name: str description: str | None None price: float 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对应仓库示例文件tutorial005_an_py310.py。此时 FastAPI 期望的请求体是{ item: { name: Foo, description: The pretender, price: 42.0, tax: 3.2 } }而不是{ name: Foo, description: The pretender, price: 42.0, tax: 3.2 }embed参数的官方定义见 fastapi/param_functions.py当embedTrue时参数会被期望作为 JSON Body 中的一个键而不是 JSON Body 本身并且文档注明声明多于一个 Body 参数时该行为会自动发生。测试佐证的典型误区test_tutorial005.py 中有一个值得注意的用例test_post_like_not_embedded当设置embedTrue后若客户端仍然发送未嵌入的扁平结构{name: Foo, price: 50.5}请求会返回 422错误位置为[body, item]——即 FastAPI 在item键下找不到值整个item字段被判定为缺失。这提醒开发者切换embed语义属于接口契约变更客户端必须同步调整否则会产生隐蔽的 422 错误。小结一个请求只能有一个 Body但这并不妨碍你在路径操作函数中声明多个 Body 参数自由混用Path、Query、Body 参数FastAPI 依据类型Pydantic 模型 vs 单个值与显式声明自动区分来源多个模型参数会自动以参数名为键嵌入请求体FastAPI 负责转换、校验并生成正确的组合 OpenAPI Schema如Body_update_item_items__item_id__put写入文档单个值参数可用Body()收进请求体并可携带gt、ge等与Query/Path一致的校验和元数据参数单个模型参数默认裸接收整个 Body用Body(embedTrue)可强制按键包裹接收从源码看该判定集中在_should_embed_body_fields()与request_body_to_args()fastapi/dependencies/utils.py中实现。以上示例文件均位于 docs_src/body_multiple_params/配套测试位于 tests/test_tutorial/test_body_multiple_params/可直接运行验证各场景的请求/响应与 OpenAPI Schema 行为。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考