跳至内容

路径参数和数值验证

与使用 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 来说,这无关紧要。它会根据参数的名称、类型和默认声明(QueryPath 等)来检测参数,它不关心顺序。

因此,您可以将函数声明为

提示

如果可能,建议使用 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

数字验证:大于或等于

使用QueryPath(以及您稍后将看到的其他方法),您可以声明数字约束。

这里,使用ge=1item_id需要是“greater than or equal”于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: greater than
  • le: less than or equal
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.00则无效。

对于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

回顾

使用QueryPath(以及您尚未见过的其他方法),您可以像使用查询参数和字符串验证一样声明元数据和字符串验证。

您还可以声明数字验证

  • gt: greater than
  • ge: greater than or equal
  • lt: less than
  • le: less than or equal

信息

QueryPath以及您稍后将看到的其他类都是通用Param类的子类。

它们都共享您已见过的用于额外验证和元数据的相同参数。

"技术细节"

当您从fastapi导入QueryPath和其他内容时,它们实际上是函数。

当被调用时,它们会返回相同名称的类的实例。

因此,您导入Query,它是一个函数。当您调用它时,它会返回一个名为Query的类的实例。

这些函数的存在(而不是直接使用类)是为了防止您的编辑器标记其类型的错误。

这样,您就可以使用正常的编辑器和编码工具,而无需添加自定义配置来忽略这些错误。