请求体 - 多参数¶
现在我们已经了解了如何使用 Path 和 Query,接下来看看请求体声明的更多高级用法。
混合使用 Path、Query 和请求体参数¶
首先,当然可以自由混合 Path、Query 和请求体参数声明,FastAPI 会自动处理。
你还可以通过将默认值设为 None,将请求体参数声明为可选参数。
from 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(title="The ID of the item to get", ge=0, le=1000)],
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
🤓 其他版本和变体
提示
如果可能,请优先使用 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: int = Path(title="The ID of the item to get", ge=0, le=1000),
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 是可选的,因为它有一个 None 的默认值。
多个请求体参数¶
在前面的示例中,路径操作期望一个包含 Item 属性的 JSON 请求体,例如
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
但你也可以声明多个请求体参数,例如 item 和 user
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
在这种情况下,FastAPI 会注意到函数中存在多个请求体参数(即两个 Pydantic 模型参数)。
因此,它会将参数名作为请求体中的键(字段名),并期望收到如下请求体:
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
},
"user": {
"username": "dave",
"full_name": "Dave Grohl"
}
}
注意
请注意,即使 item 的声明方式与之前相同,现在也要求将其置于以 item 为键的结构中。
FastAPI 会自动转换请求数据,使 item 参数接收其特定的内容,user 参数亦然。
它将执行组合数据的校验,并为 OpenAPI 模式和自动文档生成相应的文档。
请求体中的单值¶
正如 Query 和 Path 用于定义查询参数和路径参数的额外数据一样,FastAPI 也提供了对应的 Body。
例如,在扩展前面的模型时,你可能决定除了 item 和 user 之外,还在同一个请求体中包含另一个 importance 键。
如果你直接声明它,由于它是一个单值,FastAPI 会默认将其视为查询参数。
但你可以使用 Body 指示 FastAPI 将其视为另一个请求体键。
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
🤓 其他版本和变体
提示
如果可能,请优先使用 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: 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
}
同样,它会自动转换数据类型、校验、生成文档等。
多个请求体参数与查询参数¶
当然,除了请求体参数外,你还可以根据需要声明额外的查询参数。
由于单值在默认情况下会被解析为查询参数,你无需显式添加 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(gt=0)],
q: str | None = None,
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
if q:
results.update({"q": q})
return results
🤓 其他版本和变体
提示
如果可能,请优先使用 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: int = Body(gt=0),
q: str | None = None,
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
if q:
results.update({"q": q})
return results
信息
Body 也具备与 Query、Path 等后续将学到的参数相同的额外校验和元数据参数。
嵌入单个请求体参数¶
假设你只有一个来自 Pydantic 模型 Item 的 item 请求体参数。
默认情况下,FastAPI 会直接期望获取该模型的内容。
但如果你希望它像声明多个请求体参数时那样,期望一个包含 item 键的 JSON,并将模型内容放在该键内部,可以使用特殊的 Body 参数 embed。
item: Item = Body(embed=True)
如下所示:
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(embed=True)]):
results = {"item_id": item_id, "item": item}
return results
🤓 其他版本和变体
提示
如果可能,请优先使用 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: Item = Body(embed=True)):
results = {"item_id": item_id, "item": item}
return results
在这种情况下,FastAPI 将期望收到如下请求体:
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
}
而不是:
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
总结¶
你可以在路径操作函数中添加多个请求体参数,即使请求本身只能有一个请求体。
但 FastAPI 会处理它,为函数提供正确的数据,并在路径操作中校验并记录正确的架构。
你也可以声明将单值作为请求体的一部分接收。
即使只有一个参数声明,你也可以指示 FastAPI 将请求体嵌入到一个键中。