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