子相依¶
你可以建立具有「子相依」的相依項。
它們可以按你的需要,層級任意加深。
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}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
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),然後直接回傳它。
這很簡單(不太實用),但有助於我們專注於子相依如何運作。
第二個相依,同時是 "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}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
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}
來看它所宣告的參數:
- 即使這個函式本身是個相依項("dependable"),它也宣告了另一個相依(它「相依於」其他東西)。
- 它相依
query_extractor,並把其回傳值指定給參數q。
- 它相依
- 它還宣告了一個可選的
last_querycookie,型別為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}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
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}
Info
注意,在路徑操作函式中我們只宣告了一個相依項 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}
Tip
若可行,建議使用 Annotated 的版本。
async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
return {"fresh_value": fresh_value}
回顧¶
撇開這裡用到的術語不談,相依性注入(Dependency Injection) 系統其實很簡單。
它只是一些與路徑操作函式外觀相同的函式。
但它非常強大,允許你宣告任意深度巢狀的相依「圖」(樹)。
Tip
用這些簡單的例子看起來可能不那麼有用。
但在關於安全性的章節中,你會看到它有多實用。
你也會看到它能為你省下多少程式碼。