ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

FastAPI 多请求体参数实战:混用 Path/Query/Body、单值 Body 与 `embed` 内嵌完全指南

FastAPI 多请求体参数实战:混用 Path/Query/Body、单值 Body 与 `embed` 内嵌完全指南 FastAPI 多请求体参数实战混用 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 中多个请求体参数这一进阶场景如何在一个接口函数里同时声明来自路径、查询串与 JSON 请求体的参数如何把多个 Pydantic 模型以及普通标量值放进同一个请求体中以及如何用Body(embedTrue)强制请求体按指定键包裹。读完本文你将掌握 FastAPI 在单请求体 / 多请求体键之间自动转换的规则、Body的完整参数能力与底层实现依据并能直接写出可运行、可被 OpenAPI 自动文档正确描述的接口。本文以 docs/fr/docs/tutorial/body-multiple-params.md 为主线配套的示例源码位于 docs_src/body_multiple_params/其行为均有 tests/test_tutorial/test_body_multiple_params/ 下的测试用例背书。前置知识回顾在进入多请求体参数之前建议先理解两个基础概念对应仓库中的系列教程文档请求体Body解析基础见 body 教程Path与Query参数声明见 path-params 教程 与 query-params 教程。HTTP 协议本身规定一个请求只能携带一个请求体request body但这并不妨碍接口逻辑需要分组清晰、结构完整的入参。FastAPI 的做法是允许你在一个路径操作函数里声明任意多个请求体来源的参数然后由框架自动把它们按参数名包装成一个带键名的 JSON 对象去解析。混用Path、Query与请求体参数首先明确一点Path、Query和请求体Body/Pydantic 模型的声明可以自由混用FastAPI 会自动区分它们各自的来源你无需任何额外标记。请求体参数也可以声明为可选——只要给它赋默认值None。下面是最基础的混合示例完整源码见 docs_src/body_multiple_params/tutorial001_an_py310.pyfrom 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其中参数来源的判定规则一目了然参数来源依据item_id: Annotated[int, Path(...)]URL 路径显式声明为Path并附带校验ge0, le1000与文档标题q: str \| None NoneURL 查询串标量值且未声明Body默认按查询参数处理item: Item \| None None请求体类型是 Pydantic 模型默认按请求体处理[!NOTE] 注意此例中的item取自请求体且是可选的因为它的默认值是None。请求体里没有item时接口也能正常返回返回字典中不包含item键。这里所有带默认值的可选参数都排在无默认值的必选参数之后这符合 Python 函数定义语法当可选参数较多、需要更清晰的语义时可以像后续示例那样使用*,把所有参数强制为仅限关键字参数keyword-only从而避免默认值参数位于非默认值参数之前的语法限制。多个请求体参数按参数名嵌套解析上一个例子中接口期待的请求体就是Item模型本身的一对一 JSON例如{ name: Foo, description: The pretender, price: 42.0, tax: 3.2 }但 FastAPI 也允许你声明多个来自请求体的参数。以同时传入item和user为例完整源码见 docs_src/body_multiple_params/tutorial002_py310.pyfrom 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当 FastAPI 检测到函数里有多于一个请求体来源的参数本例是两个 Pydantic 模型Item和User时它会自动切换解析策略把参数名当作请求体里的键字段名期待收到的请求体形状为嵌套结构例如{ item: { name: Foo, description: The pretender, price: 42.0, tax: 3.2 }, user: { username: dave, full_name: Dave Grohl } }[!NOTE] 注意尽管item的声明方式和单请求体示例完全一样但此时它位于请求体的item键之下由 FastAPI 负责从请求体中提取对应子内容赋给item参数user同理。请求到达后FastAPI 会做类型转换与数据校验包括嵌套模型字段的校验并把最终生成的正确 schema 反映到 OpenAPI 与/docs自动文档中。源码层面的自动包装机制从源码看FastAPI 决定是否把请求体参数包装成带键对象的核心逻辑位于 fastapi/routing.py 与 fastapi/dependencies/utils.py 中routing.py通过_should_embed_body_fields见 fastapi/dependencies/utils.py判定当前路径操作是否需要对请求体做嵌入处理并把结果记录为embed_body_fields标志供后续get_dependant/get_body_field构建真正的请求体模型。判定规则可概括为只要请求体来源字段不止一个就必须嵌入否则无法从单一 JSON 中把每个键分离出来同时单个字段若显式设置了embed也强制嵌入详见后文第五节。框架随后会动态构造一个包装模型把每个请求体参数作为其一个字段。这一点在 OpenAPI 输出中可被直接观察到运行上面update_item后访问/openapi.jsoncomponents.schemas里会出现一个名为Body_update_item_items__item_id__put的合成模型其properties恰好是item、user两个键且均被标记为required。该命名规则函数名 路径 方法来源于 fastapi/utils.py 的generate_unique_id。这个完整 schema 快照正是 tests/test_tutorial/test_body_multiple_params/test_tutorial002.py 中test_openapi_schema所断言的形态。同一测试文件还覆盖了大量行为证据发送缺省整个请求体jsonNone→ 返回422错误定位在[body, item]与[body, user]信息为Field required只发送user缺item反之亦然→422仅报缺失的那一个键item内缺必填字段price→ 错误定位[body, item, price]路径参数item_id传入非整数foo→422错误定位[path, item_id]类型为int_parsing。这说明多请求体参数的校验误差别定位精确到了body.键.子字段的完整路径对客户端排查请求非常友好。请求体中的单值参数使用Body前文提到Pydantic 模型默认被当作请求体来源而对于单值标量参数例如int、str、boolFastAPI 的默认判定是查询参数。这与Query和Path各自负责查询串与路径的定位逻辑是一一对应的——FastAPI 为请求体提供了等价的Body。承接上面的例子假设除了item与user你还想在同一个请求体里多携带一个键importance一个int标量。如果直接写importance: int而不加任何注解FastAPI 会误以为它是查询参数。解决办法是用Body显式把它钉在请求体里完整源码见 docs_src/body_multiple_params/tutorial003_an_py310.pyfrom 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此时 FastAPI 期待的请求体为{ item: { name: Foo, description: The pretender, price: 42.0, tax: 3.2 }, user: { username: dave, full_name: Dave Grohl }, importance: 5 }同样地FastAPI 会对importance完成类型转换、校验与文档化。item、user两个模型键仍按前述规则嵌入importance作为第三个请求体字段被一并纳入合成模型。多请求体参数与查询参数并存真实业务里往往还需要在多个请求体键之外再加查询参数。由于标量且未加Body的参数默认就是查询参数此时连Query都可以省略直接写q: str | None None即可。看一个把三要素路径参数、多请求体键、查询参数 带校验的请求体标量全部组合起来的示例完整源码见 docs_src/body_multiple_params/tutorial004_an_py310.pyfrom 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解读该函数签名中的四种来源item_id: int→ 路径参数出现在路径模板{item_id}中item: Item、user: User→ 请求体模型分别对应请求体键item、userimportance: Annotated[int, Body(gt0)]→ 请求体键importance并且gt0表示该值必须大于 0否则返回422q: str | None None→ 查询参数可省略。开头的*,将所有参数强制为仅限关键字参数既避免了默认值参数的排序问题也让函数签名与每个参数来自哪里一目了然。update_item内部的if q:分支则体现了可选查询参数缺省时优雅降级的常见写法。[!NOTE]Body拥有和Query、Path以及后续会学到的其它参数类完全相同的一套额外校验参数与元数据参数如gt、ge、lt、le、min_length、max_length、正则、title、description等用法与Query完全一致。在 fastapi/param_functions.py 中Body的函数签名除这些共享校验参数外还显式定义了default、default_factory、embed、media_type以及alias、validation_alias、serialization_alias等用于控制字段提取与文档生成的参数说明它的能力是Query/Path的超集而非简单等价。该接口期待的是下面这样路径有 id、查询串有 q、请求体同时含三个键的复合请求{ item: { name: Foo, description: The pretender, price: 42.0, tax: 3.2 }, user: { username: dave, full_name: Dave Grohl }, importance: 5 }嵌入单个请求体参数Body(embedTrue)前几节的多请求体示例都产生了带键的嵌套请求体。如果一个接口只有一个Pydantic 模型item作为请求体来源默认情况下 FastAPI 会期待请求体内容直接就是该模型的字段——即扁平形状{ name: Foo, description: The pretender, price: 42.0, tax: 3.2 }但某些场景下你希望它即便只有一个请求体参数也保持带键的一致风格例如后续要往同一个请求体里追加字段、或客户端结构已约定外层有键名。此时使用Body的特殊参数embeditem: Annotated[Item, Body(embedTrue)]完整的实现见 docs_src/body_multiple_params/tutorial005_an_py310.pyfrom 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此时 FastAPI 期待的请求体变成{ item: { name: Foo, description: The pretender, price: 42.0, tax: 3.2 } }而不是无item键的扁平对象。embed选项从参数声明一直传到底层字段定义见 fastapi/params.pyBody对应的BodyParam内部类把embed保存在字段的field_info.embed上。而 fastapi/dependencies/utils.py 的_should_embed_body_fields会据此做最终判定只要某个请求体字段显式设置了embedTrue就强制采用带键的嵌入结构否则只有在请求体字段多于一个时才必须嵌入这样才能把各键拆分出来单个字段、未显式要求嵌入时直接以请求体本身作为模型内容解析。这解释了为什么多请求体示例里无需写embedTrue而单请求体示例里必须显式声明——两条路径殊途同归最终都由同一套嵌入逻辑驱动。小结一个 HTTP 请求虽然只有一个请求体但 FastAPI 允许你在路径操作函数里声明多个请求体参数当请求体来源参数不止一个或多个Body字段时FastAPI 自动以参数名为键包装请求体把正确数据分别注入各参数并对每个字段含嵌套模型完成校验与文档化路径参数、查询参数、请求体模型、请求体标量可以在同一个函数里自由共存FastAPI 按类型与注解自动路由路径参数来自路径模板标量默认是查询参数Pydantic 模型默认是请求体显式Body能把标量也放入请求体Body支持与Query、Path一致的校验与元数据参数并额外提供embed、media_type、alias等控制项只有一个请求体参数且需要带键形态时使用Body(embedTrue)即可强制包装上述全部行为都由仓库内示例与测试背书代码见 docs_src/body_multiple_params/覆盖缺失键、缺必填字段、路径类型错误及完整 OpenAPI schema 快照的断言见 tests/test_tutorial/test_body_multiple_params/底层判定逻辑集中在 fastapi/routing.py 与 fastapi/dependencies/utils.py 中。【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表