Подзависимости
Вы можете создавать зависимости, имеющие подзависимости.
Они могут быть глубокими, насколько вам нужно.
FastAPI позаботится о их разрешении.
Первая зависимость "dependable"
Вы можете создать первую зависимость ("dependable") так:
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}
🤓 Другие версии и варианты
from typing import Annotated, Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[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}
from typing import Union
from fastapi import Cookie, Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[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}
Подсказка
Предпочтительнее использовать версию Annotated если возможно.
from typing import Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor),
last_query: Union[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, и затем просто возвращает его.
Это довольно просто (не очень полезно), но поможет сосредоточиться на том, как работают подзависимости.
Вторая зависимость, "dependable" и "dependant"
Затем вы можете создать другую функцию-зависимость ("dependable"), которая одновременно объявляет свою собственную зависимость (так что она также является "dependant"):
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}
🤓 Другие версии и варианты
from typing import Annotated, Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[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}
from typing import Union
from fastapi import Cookie, Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[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}
Подсказка
Предпочтительнее использовать версию Annotated если возможно.
from typing import Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor),
last_query: Union[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}
Давайте сосредоточимся на объявленных параметрах:
- Несмотря на то, что эта функция сама является зависимостью ("dependable"), она также объявляет другую зависимость (она "зависит" от чего-то ещё).
- Она зависит от
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}
🤓 Другие версии и варианты
from typing import Annotated, Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[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}
from typing import Union
from fastapi import Cookie, Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: Annotated[str, Depends(query_extractor)],
last_query: Annotated[Union[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}
Подсказка
Предпочтительнее использовать версию Annotated если возможно.
from typing import Union
from fastapi import Cookie, Depends, FastAPI
app = FastAPI()
def query_extractor(q: Union[str, None] = None):
return q
def query_or_cookie_extractor(
q: str = Depends(query_extractor),
last_query: Union[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 будет знать, как вызвать эту подзависимость только один раз за запрос.
И она сохранит возвращаемое значение в "кэше" и передаст его всем "зависимым", которым это нужно в этом конкретном запросе, вместо вызова зависимости несколько раз для одного запроса.
В продвинутом сценарии, когда вам известно, что вам нужно вызвать зависимость на каждом шаге (возможно, несколько раз) в одном запросе вместо использования "кэшированного" значения, вы можете установить параметр use_cache=False при использовании Depends.
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}
Заключение
Помимо всех этих замысловатых слов, система Dependency Injection довольно проста.
Это просто функции, которые выглядят так же, как функции операций с путем.
Но она всё ещё очень мощная и позволяет вам объявлять произвольно вложенные зависимости "графы" (деревья).
Подсказка
Всё это может показаться не очень полезным с этими простыми примерами.
Но вы увидите, насколько это полезно в главах о безопасности.
И вы также увидите, сколько кода это сэкономит.
© 2018 Sebastián Ramírez
Licensed under the MIT License.
https://fastapi.tiangolo.com/tutorial/dependencies/sub-dependencies/