延迟加载视图¶
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)
需要记住的一件事是,请求前和请求后处理程序必须位于预先导入的文件中,才能在第一次请求时正常工作。任何类型的剩余装饰器也是如此。