延遲載入視圖

Flask 通常與裝飾器一起使用。裝飾器很簡單,而且 URL 就放在呼叫該特定 URL 的函式旁邊。然而,這種方法有一個缺點:這表示所有使用裝飾器的程式碼都必須預先匯入,否則 Flask 永遠不會真正找到您的函式。

如果您的應用程式必須快速匯入,這可能會成為問題。在 Google 的 App Engine 或其他系統等系統上,可能必須這樣做。因此,如果您突然注意到您的應用程式超出此方法的範圍,您可以退回到集中式的 URL 對應。

啟用集中式 URL 對應的系統是 add_url_rule() 函式。您可以使用一個檔案來設定具有所有 URL 的應用程式,而不是使用裝飾器。

轉換為集中式 URL 對應

想像一下目前的應用程式看起來有點像這樣

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    pass

@app.route('/user/<username>')
def user(username):
    pass

然後,使用集中式方法,您會有一個包含視圖的檔案(views.py),但沒有任何裝飾器

def index():
    pass

def user(username):
    pass

然後是一個設定應用程式的檔案,該檔案將函式對應到 URL

from flask import Flask
from yourapplication import views
app = Flask(__name__)
app.add_url_rule('/', view_func=views.index)
app.add_url_rule('/user/<username>', view_func=views.user)

延遲載入

到目前為止,我們只拆分了視圖和路由,但模組仍然是預先載入的。訣竅實際上是在需要時載入視圖函式。這可以使用一個輔助類別來完成,該類別的行為就像一個函式,但在首次使用時會在內部匯入真正的函式

from werkzeug.utils import import_string, cached_property

class LazyView(object):

    def __init__(self, import_name):
        self.__module__, self.__name__ = import_name.rsplit('.', 1)
        self.import_name = import_name

    @cached_property
    def view(self):
        return import_string(self.import_name)

    def __call__(self, *args, **kwargs):
        return self.view(*args, **kwargs)

這裡重要的是正確設定 __module____name__。Flask 內部使用它來找出如何命名 URL 規則,以防您沒有為規則本身提供名稱。

然後您可以定義您的中心位置來組合視圖,如下所示

from flask import Flask
from yourapplication.helpers import LazyView
app = Flask(__name__)
app.add_url_rule('/',
                 view_func=LazyView('yourapplication.views.index'))
app.add_url_rule('/user/<username>',
                 view_func=LazyView('yourapplication.views.user'))

您可以進一步最佳化這點,減少編寫此程式碼所需的按鍵次數,方法是使用一個函式來呼叫 add_url_rule(),方法是以專案名稱和點號作為字串的前綴,並根據需要將 view_func 包裝在 LazyView 中。

def url(import_name, url_rules=[], **options):
    view = LazyView(f"yourapplication.{import_name}")
    for url_rule in url_rules:
        app.add_url_rule(url_rule, view_func=view, **options)

# add a single route to the index view
url('views.index', ['/'])

# add two routes to a single function endpoint
url_rules = ['/user/','/user/<username>']
url('views.user', url_rules)

需要記住的一件事是,請求前和請求後處理器必須位於預先匯入的檔案中,才能在第一次請求時正常工作。任何種類的剩餘裝飾器也是如此。