延迟加载视图 — Flask 文档

来自菜鸟教程
Flask/docs/1.1.x/patterns/lazyloading
跳转至:导航、​搜索

延迟加载视图

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('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)

要记住的一件事是,前后请求处理程序必须位于预先导入的文件中,才能在第一个请求上正常工作。 任何类型的剩余装饰器也是如此。