路径参数和数值验证¶
与使用 Query
为查询参数声明更多验证和元数据的方式相同,您可以使用 Path
为路径参数声明相同类型的验证和元数据。
导入 Path¶
首先,从 fastapi
中导入 Path
,并导入 Annotated
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Annotated, Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Union
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建议使用 Annotated
版本。
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: str | None = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建议使用 Annotated
版本。
from typing import Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: Union[str, None] = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
信息
FastAPI 在 0.95.0 版本中添加了对 Annotated
的支持(并开始推荐它)。
如果您使用的是旧版本,则在尝试使用 Annotated
时会出现错误。
在使用 Annotated
之前,请确保您将 FastAPI 版本升级到至少 0.95.1。
声明元数据¶
您可以声明与 Query
相同的所有参数。
例如,要为路径参数 item_id
声明一个 title
元数据值,您可以键入
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[str | None, Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Annotated, Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from typing import Union
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")],
q: Annotated[Union[str, None], Query(alias="item-query")] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建议使用 Annotated
版本。
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: str | None = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建议使用 Annotated
版本。
from typing import Union
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: int = Path(title="The ID of the item to get"),
q: Union[str, None] = Query(default=None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
注意
路径参数始终是必需的,因为它必须是路径的一部分。即使您使用 None
声明它或设置了默认值,它也不会影响任何内容,它仍然始终是必需的。
按需排序参数¶
提示
如果您使用 Annotated
,这可能并不那么重要或必要。
假设您想将查询参数 q
声明为必需的 str
。
并且您不需要为该参数声明其他任何内容,因此您实际上不需要使用 Query
。
但是您仍然需要为 item_id
路径参数使用 Path
。并且由于某种原因,您不想使用 Annotated
。
如果您在没有“default”的值之前放置一个带有“default”的值,Python 会报错。
但是您可以重新排序它们,并将没有默认值的值(查询参数 q
)放在前面。
对于 FastAPI 来说,这无关紧要。它会根据参数的名称、类型和默认声明(Query
、Path
等)来检测参数,它不关心顺序。
因此,您可以将函数声明为
提示
如果可能,建议使用 Annotated
版本。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
但请记住,如果您使用 Annotated
,您就不会遇到此问题,因为您没有为 Query()
或 Path()
使用函数参数默认值,所以顺序无关紧要。
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
q: str, item_id: Annotated[int, Path(title="The ID of the item to get")]
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
按需排序参数,技巧¶
提示
如果您使用 Annotated
,这可能并不那么重要或必要。
这是一个可能很方便的 **小技巧**,但您不会经常需要它。
如果您想要
- 声明
q
查询参数,不使用Query
也不使用任何默认值 - 使用
Path
声明路径参数item_id
- 以不同的顺序排列它们
- 不使用
Annotated
…Python 有一个用于此的小特殊语法。
将 *
作为函数的第一个参数传递。
Python 不会对 *
做任何事情,但它会知道所有后续参数都应该作为关键字参数(键值对)调用,也称为 kwargs
。即使它们没有默认值。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
使用 Annotated
更好¶
请记住,如果您使用的是Annotated
,因为您没有使用函数参数的默认值,所以您不会遇到此问题,并且您可能不需要使用*
。
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get")], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
数字验证:大于或等于¶
使用Query
和Path
(以及您稍后将看到的其他方法),您可以声明数字约束。
这里,使用ge=1
,item_id
需要是“g
reater than or e
qual”于1
的整数。
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建议使用 Annotated
版本。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*, item_id: int = Path(title="The ID of the item to get", ge=1), q: str
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
数字验证:大于和小于或等于¶
同样的规则也适用于
gt
:g
reatert
hanle
:l
ess than ore
qual
from typing import Annotated
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
from fastapi import FastAPI, Path
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)],
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
提示
如果可能,建议使用 Annotated
版本。
from fastapi import FastAPI, Path
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", gt=0, le=1000),
q: str,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results
数字验证:浮点数,大于和小于¶
数字验证也适用于float
值。
这里,能够声明gt
而不是仅声明ge
变得很重要。通过它,您可以例如要求某个值必须大于0
,即使它小于1
。
因此,0.5
将是有效值。但0.0
或0
则无效。
对于lt
也是如此。
from typing import Annotated
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: str,
size: Annotated[float, Query(gt=0, lt=10.5)],
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
from fastapi import FastAPI, Path, Query
from typing_extensions import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)],
q: str,
size: Annotated[float, Query(gt=0, lt=10.5)],
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
提示
如果可能,建议使用 Annotated
版本。
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
item_id: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: str,
size: float = Query(gt=0, lt=10.5),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if size:
results.update({"size": size})
return results
回顾¶
使用Query
、Path
(以及您尚未见过的其他方法),您可以像使用查询参数和字符串验证一样声明元数据和字符串验证。
您还可以声明数字验证
gt
:g
reatert
hange
:g
reater than ore
quallt
:l
esst
hanle
:l
ess than ore
qual
信息
Query
、Path
以及您稍后将看到的其他类都是通用Param
类的子类。
它们都共享您已见过的用于额外验证和元数据的相同参数。
"技术细节"
当您从fastapi
导入Query
、Path
和其他内容时,它们实际上是函数。
当被调用时,它们会返回相同名称的类的实例。
因此,您导入Query
,它是一个函数。当您调用它时,它会返回一个名为Query
的类的实例。
这些函数的存在(而不是直接使用类)是为了防止您的编辑器标记其类型的错误。
这样,您就可以使用正常的编辑器和编码工具,而无需添加自定义配置来忽略这些错误。