Flask 擴(kuò)展的代碼

2021-08-11 21:18 更新

下面是用來復(fù)制/粘貼的 flask_sqlite3.py 的內(nèi)容:

import sqlite3
from flask import current_app

# Find the stack on which we want to store the database connection.
# Starting with Flask 0.9, the _app_ctx_stack is the correct one,
# before that we need to use the _request_ctx_stack.
try:
    from flask import _app_ctx_stack as stack
except ImportError:
    from flask import _request_ctx_stack as stack


class SQLite3(object):

    def __init__(self, app=None):
        self.app = app
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        app.config.setdefault('SQLITE3_DATABASE', ':memory:')
        # Use the newstyle teardown_appcontext if it's available,
        # otherwise fall back to the request context
        if hasattr(app, 'teardown_appcontext'):
            app.teardown_appcontext(self.teardown)
        else:
            app.teardown_request(self.teardown)

    def connect(self):
        return sqlite3.connect(current_app.config['SQLITE3_DATABASE'])

    def teardown(self, exception):
        ctx = stack.top
        if hasattr(ctx, 'sqlite3_db'):
            ctx.sqlite3_db.close()

    @property
    def connection(self):
        ctx = stack.top
        if ctx is not None:
            if not hasattr(ctx, 'sqlite3_db'):
                ctx.sqlite3_db = self.connect()
            return ctx.sqlite3_db

那么這是這些代碼做的事情:

  1. __init__ 方法接受一個可選的應(yīng)用對象,并且如果提供,會調(diào)用 init_app 。

  2. init_app 方法使得 SQLite3 對象不需要應(yīng)用對象就可以實(shí)例化。這個方法 支持工廠模式來創(chuàng)建應(yīng)用。 init_app 會為數(shù)據(jù)庫設(shè)定配置,如果不提供配置,默 認(rèn)是一個內(nèi)存中的數(shù)據(jù)庫。此外, init_app 方法附加了 teardown 處理器。 它會試圖使用新樣式的應(yīng)用上下文處理器,并且如果它不存在,退回到請求上下文處理 器。

  3. 接下來,我們定義了 connect 方法來打開一個數(shù)據(jù)庫連接。

  4. 最后,我們添加一個 connection 屬性,首次訪問時打開數(shù)據(jù)庫連接,并把它存儲 在上下文。這也是處理資源的推薦方式:在資源第一次使用時惰性獲取資源。

    注意這里,我們把數(shù)據(jù)庫連接通過 _app_ctx_stack.top 附加到應(yīng)用上下文 的棧頂。擴(kuò)展應(yīng)該使用上下文的棧頂來存儲它們自己的信息,并使用足夠復(fù)雜的 名稱。注意如果應(yīng)用使用不支持它的老版本的 Flask 我們退回到 _request_ctx_stack.top 。

那么為什么我們決定在此使用基于類的方法?因?yàn)槭褂梦覀兊臄U(kuò)展的情況看起來 會是這樣:

from flask import Flask
from flask_sqlite3 import SQLite3

app = Flask(__name__)
app.config.from_pyfile('the-config.cfg')
db = SQLite3(app)

你之后可以在視圖中這樣使用數(shù)據(jù)庫:

@app.route('/')
def show_all():
    cur = db.connection.cursor()
    cur.execute(...)

同樣地,如果你在請求之外,而你在使用支持應(yīng)用上下文 Flask 0.9 或之后的版本, 你可以用同樣的方法使用數(shù)據(jù)庫:

with app.app_context():
    cur = db.connection.cursor()
    cur.execute(...)

with 塊的最后,銷毀處理器會自動執(zhí)行。

此外, init_app 方法用于支持創(chuàng)建應(yīng)用的工廠模式:

db = Sqlite3()
# Then later on.
app = create_app('the-config.cfg')
db.init_app(app)

記住已審核的 Flask 擴(kuò)展需要支持用工廠模式來創(chuàng)建應(yīng)用(下面會解釋)。

init_app 的注意事項(xiàng)

如你所見, init_app 不分配 appself 。這是故意的!基于 類的 Flask 擴(kuò)展必須只在應(yīng)用傳遞到構(gòu)造函數(shù)時在對象上存儲應(yīng)用。這告訴擴(kuò) 展:我對使用多個應(yīng)用沒有興趣。

當(dāng)擴(kuò)展需要找出當(dāng)前的應(yīng)用且它沒有一個指向其的引用時,必須使用 current_app 上下文局域變量或用一種你可以顯式傳遞應(yīng)用的 方法更改 API 。


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號