跳到内容

子依赖项

你可以创建拥有子依赖项的依赖项。

它们的嵌套深度可以根据需要任意设定。

FastAPI 会负责解析它们。

第一个依赖项“可依赖项”

你可以创建一个第一个依赖项(“可依赖项”),例如:

from typing import Annotated

from fastapi import Cookie, Depends, FastAPI

app = FastAPI()


def query_extractor(q: str | None = None):
    return q


def query_or_cookie_extractor(
    q: Annotated[str, Depends(query_extractor)],
    last_query: Annotated[str | None, Cookie()] = None,
):
    if not q:
        return last_query
    return q


@app.get("/items/")
async def read_query(
    query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
    return {"q_or_cookie": query_or_default}
🤓 其他版本和变体

提示

如果可能,请优先使用 Annotated 版本。

from fastapi import Cookie, Depends, FastAPI

app = FastAPI()


def query_extractor(q: str | None = None):
    return q


def query_or_cookie_extractor(
    q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None)
):
    if not q:
        return last_query
    return q


@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
    return {"q_or_cookie": query_or_default}

它声明了一个可选的查询参数 q 作为 str,然后将其返回。

这非常简单(没什么实际用处),但有助于我们专注于理解子依赖项的工作原理。

第二个依赖项,“可依赖项”和“依赖者”

然后你可以创建另一个依赖函数(一个“可依赖项”),它同时声明了自己的依赖项(因此它也是一个“依赖者”)。

from typing import Annotated

from fastapi import Cookie, Depends, FastAPI

app = FastAPI()


def query_extractor(q: str | None = None):
    return q


def query_or_cookie_extractor(
    q: Annotated[str, Depends(query_extractor)],
    last_query: Annotated[str | None, Cookie()] = None,
):
    if not q:
        return last_query
    return q


@app.get("/items/")
async def read_query(
    query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
    return {"q_or_cookie": query_or_default}
🤓 其他版本和变体

提示

如果可能,请优先使用 Annotated 版本。

from fastapi import Cookie, Depends, FastAPI

app = FastAPI()


def query_extractor(q: str | None = None):
    return q


def query_or_cookie_extractor(
    q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None)
):
    if not q:
        return last_query
    return q


@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
    return {"q_or_cookie": query_or_default}

让我们专注于声明的参数:

  • 尽管这个函数本身是一个依赖项(“可依赖项”),但它也声明了另一个依赖项(它“依赖”于其他东西)。
    • 它依赖于 query_extractor,并将该函数返回的值赋给参数 q
  • 它还声明了一个可选的 last_query cookie,类型为 str
    • 如果用户没有提供查询参数 q,我们就使用之前保存在 cookie 中的上一次查询记录。

使用依赖项

然后我们可以这样使用该依赖项:

from typing import Annotated

from fastapi import Cookie, Depends, FastAPI

app = FastAPI()


def query_extractor(q: str | None = None):
    return q


def query_or_cookie_extractor(
    q: Annotated[str, Depends(query_extractor)],
    last_query: Annotated[str | None, Cookie()] = None,
):
    if not q:
        return last_query
    return q


@app.get("/items/")
async def read_query(
    query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
    return {"q_or_cookie": query_or_default}
🤓 其他版本和变体

提示

如果可能,请优先使用 Annotated 版本。

from fastapi import Cookie, Depends, FastAPI

app = FastAPI()


def query_extractor(q: str | None = None):
    return q


def query_or_cookie_extractor(
    q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None)
):
    if not q:
        return last_query
    return q


@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
    return {"q_or_cookie": query_or_default}

注意

请注意,我们在路径操作函数中只声明了一个依赖项:query_or_cookie_extractor

FastAPI 会知道它必须先解析 query_extractor,以便在调用 query_or_cookie_extractor 时将解析结果传递给它。

graph TB

query_extractor(["query_extractor"])
query_or_cookie_extractor(["query_or_cookie_extractor"])

read_query["/items/"]

query_extractor --> query_or_cookie_extractor --> read_query

多次使用同一个依赖项

如果你的某个依赖项在同一个路径操作中被多次声明,例如多个依赖项都有一个共同的子依赖项,FastAPI 会确保每个请求只调用该子依赖项一次。

它会将返回值保存在 “缓存” 中,并在该特定请求中将其传递给所有需要它的“依赖者”,而不是对同一个请求多次调用该依赖项。

在高级场景中,如果你确定需要在同一个请求的每个步骤中(可能多次)调用依赖项,而不是使用“缓存”值,你可以在使用 Depends 时设置参数 use_cache=False

async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
    return {"fresh_value": fresh_value}

提示

如果可能,请优先使用 Annotated 版本。

async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
    return {"fresh_value": fresh_value}

回顾

抛开这里使用的所有华丽词汇,依赖注入系统其实非常简单。

它们仅仅是看起来与路径操作函数相同的函数。

但它依然非常强大,允许你声明任意深度嵌套的依赖“图”(树)。

提示

所有这些在简单的示例中可能看起来用处不大。

但你将在关于安全的章节中看到它的强大之处。

你还会看到它能为你节省大量的代码。