请求体 - 多个参数¶
至此,我们已经学习了如何使用 Path
和 Query
,接下来,继续学习声明请求体的高级用法。
混用 Path
、Query
和请求体参数¶
首先,声明中可以随意混用 Path
、Query
和请求体参数,FastAPI 知道该如何处理。
默认值为 None
时,请求体参数是可选的:
from typing import Union
from fastapi import FastAPI, Path
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[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: Union[str, None] = None,
item: Union[Item, None] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if item:
results.update({"item": item})
return results
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
。
多个请求体参数¶
上例中,路径操作预期 JSON 请求体中的 Item
包含如下属性:
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
但也可以声明多个请求体参数,例如 item
和 user
:
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class User(BaseModel):
username: str
full_name: Union[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
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
参数会接收指定的内容。
FastAPI 不仅会校验复合数据,还会在 OpenAPI 概图和 API 文档显示。
请求体中的单值¶
除了 Query
和 Path
可以为查询参数与路径参数定义更多数据之外,FastAPI 还提供了类似的 Body
函数。
例如,扩展上述模型,除了 item
和 user
之外,还要在同一请求体中,添加另一个键 importance
。
如果直接声明该参数,因为 importance
是单值,FastAPI 会把它识别为查询参数。
此时,就需要使用 Body
让 FastAPI 把它当作请求体的键。
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class User(BaseModel):
username: str
full_name: Union[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
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
}
FastAPI 仍会执行转换数据类型、校验、生成文档等操作。
多个请求体参数和查询参数¶
除了请求体参数外,还可以声明更多查询参数。
默认情况下,单值会被解释为查询参数,因此不必显式添加 Query
,只需用以下代码:
q: Union[str, None] = None
Python 3.10 及以上版本:
q: str | None = None
示例如下:
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class User(BaseModel):
username: str
full_name: Union[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: Union[str, None] = None
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
if q:
results.update({"q": q})
return results
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 会直接调用请求体。
但是,如果希望 JSON 中包含 item
键,且模型内容都在该键之下,就要参照声明更多请求体参数的方式,使用 Body
的 embed
参数:
item: Item = Body(..., embed=True)
示例如下:
from typing import Union
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[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
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 会进行处理,为函数提供正确的数据,并进行校验,还能在 API 文档中显示正确的路径操作概图。
请求体还可以接收多个单值。
只声明单个请求体参数时,FastAPI 也可以把请求体嵌入到键里。