FastAPI 支持在完成后執(zhí)行一些額外步驟的依賴(lài)項(xiàng)。
為此,請(qǐng)使用yield代替return,并在之后編寫(xiě)額外的步驟。
提示
確保使用yield一次。
技術(shù)細(xì)節(jié)
任何可用于以下功能的有效函數(shù):
用作FastAPI依賴(lài)項(xiàng)是有效的。
事實(shí)上,F(xiàn)astAPI 在內(nèi)部使用了這兩個(gè)裝飾器。
例如,您可以使用它來(lái)創(chuàng)建數(shù)據(jù)庫(kù)會(huì)話并在完成后關(guān)閉它。
yield在發(fā)送響應(yīng)之前,只執(zhí)行包含該語(yǔ)句之前的代碼:
async def get_db():
db = DBSession()
try:
yield db
finally:
db.close()
產(chǎn)生的值是注入到路徑操作和其他依賴(lài)項(xiàng)中的值:
async def get_db():
db = DBSession()
try:
yield db
finally:
db.close()
yield響應(yīng)傳遞后執(zhí)行語(yǔ)句后面的代碼:
async def get_db():
db = DBSession()
try:
yield db
finally:
db.close()
提示
您可以使用async或 正常功能。
FastAPI會(huì)對(duì)每個(gè)都做正確的事情,就像普通的依賴(lài)一樣。
如果您try在依賴(lài)項(xiàng)中使用塊 with yield,您將收到使用該依賴(lài)項(xiàng)時(shí)拋出的任何異常。
例如,如果某些代碼在中間、另一個(gè)依賴(lài)項(xiàng)或路徑操作中的某個(gè)點(diǎn)使數(shù)據(jù)庫(kù)事務(wù)“回滾”或創(chuàng)建任何其他錯(cuò)誤,您將在依賴(lài)項(xiàng)中收到異常。
因此,您可以使用except SomeException.
同樣,您可以使用finally來(lái)確保執(zhí)行退出步驟,無(wú)論是否有異常。
async def get_db():
db = DBSession()
try:
yield db
finally:
db.close()
您可以擁有任何大小和形狀的子依賴(lài)項(xiàng)和子依賴(lài)項(xiàng)的“樹(shù)”,并且它們中的任何一個(gè)或全部都可以使用yield.
FastAPI將確保每個(gè)依賴(lài)項(xiàng)中的“退出代碼”以yield正確的順序運(yùn)行。
例如,dependency_c可以對(duì)一個(gè)依賴(lài)dependency_b,并dependency_b于dependency_a:
from fastapi import Depends
async def dependency_a():
dep_a = generate_dep_a()
try:
yield dep_a
finally:
dep_a.close()
async def dependency_b(dep_a=Depends(dependency_a)):
dep_b = generate_dep_b()
try:
yield dep_b
finally:
dep_b.close(dep_a)
async def dependency_c(dep_b=Depends(dependency_b)):
dep_c = generate_dep_c()
try:
yield dep_c
finally:
dep_c.close(dep_b)
所有這些都可以使用yield.
在這種情況下dependency_c,要執(zhí)行其退出代碼,需要來(lái)自dependency_b(此處命名為dep_b)的值仍然可用。
并且,反過(guò)來(lái),dependency_b需要來(lái)自dependency_a(此處命名為dep_a)的值可用于其退出代碼。
from fastapi import Depends
async def dependency_a():
dep_a = generate_dep_a()
try:
yield dep_a
finally:
dep_a.close()
async def dependency_b(dep_a=Depends(dependency_a)):
dep_b = generate_dep_b()
try:
yield dep_b
finally:
dep_b.close(dep_a)
async def dependency_c(dep_b=Depends(dependency_b)):
dep_c = generate_dep_c()
try:
yield dep_c
finally:
dep_c.close(dep_b)
同樣,你可以有依賴(lài)yield和return混合。
并且您可能有一個(gè)依賴(lài)項(xiàng),它需要其他幾個(gè)依賴(lài)項(xiàng)yield,等等。
您可以擁有所需的任何依賴(lài)項(xiàng)組合。
FastAPI將確保一切以正確的順序運(yùn)行。
技術(shù)細(xì)節(jié)
這要?dú)w功于 Python 的Context Managers。
FastAPI在內(nèi)部使用它們來(lái)實(shí)現(xiàn)這一點(diǎn)。
您已經(jīng)看到可以使用依賴(lài)項(xiàng),yield并且可以使用try捕獲異常的塊。
它可能是誘人引發(fā)HTTPException的退出代碼或類(lèi)似,后yield。但它不會(huì)工作。
依賴(lài)中的退出代碼在Exception Handlers之后yield執(zhí)行。在退出代碼中(在 之后)沒(méi)有任何捕獲依賴(lài)項(xiàng)引發(fā)的異常。 yield
因此,如果您在HTTPException之后引發(fā) ,則yield捕獲HTTPExceptions 并返回 HTTP 400 響應(yīng)的默認(rèn)(或任何自定義)異常處理程序?qū)⒉辉儆糜诓东@該異常。
這就是允許任何設(shè)置在依賴(lài)項(xiàng)(例如數(shù)據(jù)庫(kù)會(huì)話)中的東西,例如,被后臺(tái)任務(wù)使用。
后臺(tái)任務(wù)在響應(yīng)發(fā)送后運(yùn)行。所以沒(méi)有辦法提高 anHTTPException因?yàn)樯踔翛](méi)有辦法改變已經(jīng)發(fā)送的響應(yīng)。
但是,如果后臺(tái)任務(wù)創(chuàng)建了數(shù)據(jù)庫(kù)錯(cuò)誤,至少您可以使用 回滾或干凈地關(guān)閉依賴(lài)項(xiàng)中的會(huì)話yield,并且可以記錄錯(cuò)誤或?qū)⑵鋱?bào)告給遠(yuǎn)程跟蹤系統(tǒng)。
如果您知道某些代碼可能引發(fā)異常,請(qǐng)執(zhí)行最正常/“Pythonic”的操作并try在該部分代碼中添加一個(gè)塊。
如果您想在返回響應(yīng)之前處理自定義異常并可能修改響應(yīng),甚至可能引發(fā)HTTPException,請(qǐng)創(chuàng)建自定義異常處理程序。
提示
您仍然可以引發(fā)異常,包括HTTPException 之前的yield。但不是之后。
執(zhí)行的順序或多或少像這個(gè)圖。時(shí)間從上到下流動(dòng)。每一列都是交互或執(zhí)行代碼的部分之一。
信息
只會(huì)向客戶(hù)端發(fā)送一個(gè)響應(yīng)。它可能是錯(cuò)誤響應(yīng)之一,也可能是來(lái)自路徑操作的響應(yīng)。
在發(fā)送這些響應(yīng)之一后,不能再發(fā)送其他響應(yīng)。
提示
此圖顯示HTTPException,但您也可以引發(fā)任何其他異常,您為其創(chuàng)建自定義異常處理程序。并且該異常將由該自定義異常處理程序而不是依賴(lài)項(xiàng)退出代碼處理。
但是如果你引發(fā)一個(gè)異常處理程序沒(méi)有處理的異常,它將由依賴(lài)項(xiàng)的退出代碼處理。
“上下文管理器”是您可以在with語(yǔ)句中使用的任何 Python 對(duì)象。
例如,您可以使用with讀取文件:
with open("./somefile.txt") as f:
contents = f.read()
print(contents)
在下面,它open("./somefile.txt")創(chuàng)建了一個(gè)稱(chēng)為“上下文管理器”的對(duì)象。
當(dāng)with塊完成時(shí),它確保關(guān)閉文件,即使有異常。
當(dāng)您使用 來(lái)創(chuàng)建依賴(lài)項(xiàng)時(shí)yield,F(xiàn)astAPI會(huì)在內(nèi)部將其轉(zhuǎn)換為上下文管理器,并將其與其他一些相關(guān)工具結(jié)合起來(lái)。
警告
這或多或少是一個(gè)“高級(jí)”的想法。
如果您剛剛開(kāi)始使用FastAPI,您可能想暫時(shí)跳過(guò)它。
在 Python 中,您可以通過(guò)使用兩種方法創(chuàng)建一個(gè)類(lèi)__enter__()__exit__()來(lái)創(chuàng)建上下文管理器:和。
您還可以通過(guò)在依賴(lài)函數(shù)中使用 或語(yǔ)句在FastAPI依賴(lài)中使用它們:yieldwithasync with
class MySuperContextManager:
def __init__(self):
self.db = DBSession()
def __enter__(self):
return self.db
def __exit__(self, exc_type, exc_value, traceback):
self.db.close()
async def get_db():
with MySuperContextManager() as db:
yield db
提示
創(chuàng)建上下文管理器的另一種方法是:
使用它們來(lái)裝飾帶有單個(gè)yield.
這就是FastAPI 在內(nèi)部用于與yield.
但是您不必為 FastAPI 依賴(lài)項(xiàng)使用裝飾器(并且您不應(yīng)該這樣做)。
FastAPI 將在內(nèi)部為您完成。
更多建議: