FastAPI教程 與yield的依賴關(guān)系

2021-11-03 09:37 更新

FastAPI 支持在完成后執(zhí)行一些額外步驟的依賴項。

為此,請使用yield代替return,并在之后編寫額外的步驟。

提示

確保使用yield一次。

技術(shù)細節(jié)

任何可用于以下功能的有效函數(shù):

用作FastAPI依賴項是有效的。

事實上,F(xiàn)astAPI 在內(nèi)部使用了這兩個裝飾器。

數(shù)據(jù)庫依賴項 yield

例如,您可以使用它來創(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會對每個都做正確的事情,就像普通的依賴一樣。

依賴yield和try

如果您try在依賴項中使用塊 with yield,您將收到使用該依賴項時拋出的任何異常。

例如,如果某些代碼在中間、另一個依賴項或路徑操作中的某個點使數(shù)據(jù)庫事務“回滾”或創(chuàng)建任何其他錯誤,您將在依賴項中收到異常。

因此,您可以使用except SomeException.

同樣,您可以使用finally來確保執(zhí)行退出步驟,無論是否有異常。

async def get_db():
    db = DBSession()
    try:
        yield db
    finally:
        db.close()

子依賴項 yield

您可以擁有任何大小和形狀的子依賴項和子依賴項的“樹”,并且它們中的任何一個或全部都可以使用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)這一點。

與yield和的依賴關(guān)系HTTPException

您已經(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é)合起來。

在依賴項中使用上下文管理器 yield

警告

這或多或少是一個“高級”的想法。

如果您剛剛開始使用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)部為您完成。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號