Ленивая загрузка представлений

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__ and __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)

Следует помнить, что обработчики запросов до и после должны находиться в файле, который импортируется заранее, чтобы правильно работать при первом запросе. То же самое относится к любому оставшемуся декоратору.

Вернуться на верх