Spec-Zone.ru › FastAPI

Подзависимости

Вы можете создавать зависимости, у которых есть подзависимости.

Их глубина может быть любой.

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 возвращаемое ею значение.
  • Она также объявляет необязательную cookie last_query типа 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}

Итоги

Если не обращать внимания на все эти сложные термины, система внедрения зависимостей довольно проста.

Это просто функции, похожие на функции операций пути.

Но при этом она очень мощная и позволяет объявлять сколь угодно глубоко вложенные «графы» зависимостей (деревья).

Совет

В этих простых примерах всё это может показаться не очень полезным.

Но вы увидите, насколько это полезно, в главах о безопасности.

Вы также увидите, сколько кода это поможет вам сэкономить.

© 2018 Sebastián Ramírez
Licensed under the MIT License.
https://fastapi.tiangolo.com/tutorial/dependencies/sub-dependencies/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API