應用程式情境

應用程式情境會在請求、CLI 命令或其他活動期間追蹤應用程式層級的資料。與其將應用程式傳遞到每個函式,不如改為存取 current_appg 代理物件。

這與請求情境類似,後者會在請求期間追蹤請求層級的資料。當請求情境被推送時,也會推送對應的應用程式情境。

情境的目的

Flask 應用程式物件具有屬性,例如 config,這些屬性在視圖和 CLI 命令中存取時非常有用。然而,在專案的模組中匯入 app 實例容易產生循環匯入問題。當使用應用程式工廠模式或編寫可重複使用的藍圖擴充套件時,根本沒有 app 實例可以匯入。

Flask 使用應用程式情境解決了這個問題。與其直接引用 app,不如使用 current_app 代理物件,它指向處理目前活動的應用程式。

Flask 在處理請求時會自動推送應用程式情境。在請求期間執行的視圖函式、錯誤處理常式和其他函式將可以存取 current_app

當執行使用 Flask.cli@app.cli.command() 註冊的 CLI 命令時,Flask 也會自動推送應用程式情境。

情境的生命週期

應用程式情境會根據需要建立和銷毀。當 Flask 應用程式開始處理請求時,它會推送應用程式情境和請求情境。當請求結束時,它會彈出請求情境,然後彈出應用程式情境。通常,應用程式情境的生命週期與請求相同。

請參閱請求情境以獲取有關情境如何運作以及請求完整生命週期的更多資訊。

手動推送情境

如果您嘗試在應用程式情境外存取 current_app 或任何使用它的東西,您會收到此錯誤訊息

RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that
needed to interface with the current application object in some way.
To solve this, set up an application context with app.app_context().

如果在設定應用程式時看到該錯誤,例如在初始化擴充套件時,您可以手動推送情境,因為您可以直接存取 app。在 with 區塊中使用 app_context(),並且在該區塊中運行的所有內容都將可以存取 current_app

def create_app():
    app = Flask(__name__)

    with app.app_context():
        init_db()

    return app

如果您在程式碼的其他地方看到該錯誤,而不是與設定應用程式相關,則很可能表示您應該將該程式碼移至視圖函式或 CLI 命令中。

儲存資料

應用程式情境是在請求或 CLI 命令期間儲存通用資料的好地方。Flask 為此目的提供了 g 物件。它是一個簡單的命名空間物件,其生命週期與應用程式情境相同。

注意

g 名稱代表「全域」,但這是指資料在情境內是全域的。在情境結束後,g 上的資料會遺失,並且它不是在請求之間儲存資料的適當位置。使用 session 或資料庫來跨請求儲存資料。

g 的常見用途是在請求期間管理資源。

  1. get_X() 會在資源 X 不存在時建立它,並將其快取為 g.X

  2. teardown_X() 會在資源存在時關閉或以其他方式釋放資源。它註冊為 teardown_appcontext() 處理常式。

例如,您可以使用此模式管理資料庫連線

from flask import g

def get_db():
    if 'db' not in g:
        g.db = connect_to_database()

    return g.db

@app.teardown_appcontext
def teardown_db(exception):
    db = g.pop('db', None)

    if db is not None:
        db.close()

在請求期間,每次呼叫 get_db() 都會傳回相同的連線,並且它會在請求結束時自動關閉。

您可以使用 LocalProxyget_db() 建立新的情境本地代理

from werkzeug.local import LocalProxy
db = LocalProxy(get_db)

存取 db 將在內部呼叫 get_db,方式與 current_app 的運作方式相同。

事件和訊號

當應用程式情境被彈出時,應用程式將呼叫使用 teardown_appcontext() 註冊的函式。

發送以下訊號:appcontext_pushedappcontext_tearing_downappcontext_popped