Сообщить об ошибке.

Контекст веб-приложения на Flask в Python.

Контекст приложения на Flask отслеживает данные уровня приложения во время запроса, команды CLI или других действий. Вместо передачи каждой функции экземпляра веб-приложения, Flask осуществляет доступ к прокси-объектам приложения flask.current_app и flask.g.
Такое поведение похоже на контекст запроса, который отслеживает данные уровня запроса во время самого запроса к веб-приложению. Соответствующий контекст веб-приложения передается при передаче контекста запроса.

Содержание:


Цель контекста приложения Flask.

Объект приложения Flask имеет атрибуты, такие как Flask.config, которые полезны для осуществления к ним доступа из кода веб-представления. Но при импорте экземпляра приложения в модули проекта возникают проблемы с циклическим импортом. При использовании шаблона фабрики приложений, многоразовых схем blueprint или расширений, экземпляра приложения (app) для импорта вообще не будет.
Фреймворк Flask решает эту проблему с помощью контекста приложения. Вместо того, чтобы ссылаться на экземпляр приложения напрямую, используется прокси-объект flask.current_app, который указывает на само приложение, обрабатывающее текущую активность.
Flask автоматически проталкивает контекст приложения при обработке запроса. Функции-представления (views), обработчики ошибок и другие функции, которые выполняются во время запроса, будут иметь доступ к flask.current_app.
Flask также автоматически проталкивает контекст приложения при запуске команд CLI, зарегистрированных в Flask.cli, с помощью декоратора @app.cli.command().

Время жизни контекста приложения Flask.

Контекст приложения создается и уничтожается по мере необходимости. Когда приложение Flask начинает обрабатывать запрос, то оно проталкивает контекст приложения и контекст запроса. Когда запрос завершается, появляется контекст запроса, а затем контекст приложения. Обычно у контекста приложения такое же время жизни, как у запроса.
Для получения дополнительной информации о том, как работают контексты и полный жизненный цикл запроса смотрите материал "Контекст запроса веб-приложения на Flask".

Проталкивание контекста вручную.

Если попытаться получить доступ к current_app или чему-либо, что его использует вне контекста приложения, то появляется следующее сообщение об ошибке:
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that
needed to interface with the current application object in some way.
To solve this, set up an application context with app.app_context().
Если эта ошибка появляется при настройке веб-приложения, например, при инициализации расширения, то можно отправить контекст вручную, т.к. есть прямой доступ к приложению. Используйте app.app_context() в блоке with, и все, что выполняется в блоке, будет иметь доступ к flask.current_app.
def create_app():
    app = Flask(__name__)

    with app.app_context():
        init_db()

    return app
Если эта ошибка появляется где-то еще в коде, не связанном с настройкой приложения, то это, скорее всего, указывает на то, что этот код необходимо переместить в функцию-представление или команду CLI.

Хранение общих данных во время запроса.

Контекст приложения - хорошее место для хранения общих данных во время запроса. Для этой цели Flask предоставляет глобальный объект flask.g . Это простой объект пространства имен, имеющий то же время жизни, что и контекст приложения.
Примечание. Имя g означает "глобальный", но это относится к данным, которые являются глобальными в контексте. Данные в g теряются после завершения контекста, и это не подходящее место для хранения данных, которые передаются от запроса к запросу. Для передачи данных между запросами необходимо использовать сессии/сеансы или базу данных.
Обычно flask.g используется для управления ресурсами во время запроса.
  • get_X() создает ресурс X, если он не существует, кэшируя его как g.X.
  • teardown_X() закрывает или иным образом освобождает ресурс, если он существует. Он зарегистрирован как обработчик app.teardown_appcontext().
Например, можно управлять подключением к базе данных, используя этот шаблон:
from flask import g

def get_db():
    if 'db' not in g:
        g.db = connect_to_database()
    return g.db

@app.teardown_appcontext
def teardown_db(exception):
    db = g.pop('db', None)
    if db is not None:
        db.close()
Во время запроса каждый вызов get_db() будет возвращать одно и то же соединение, и оно будет автоматически закрыто в конце запроса.
Можете использовать werkzeug.local.LocalProxy, чтобы сделать новый контекст локальным из get_db():
from werkzeug.local import LocalProxy
db = LocalProxy(get_db)
Доступ к db вызовет get_db() внутренне, так же, как работает flask.current_app.

Если работаете над расширением для Flask, то flask.g следует зарезервировать для пользовательского кода. Конечно можно хранить какие-то внутренние данные в самом контексте, но для этих данных обязательно следует использовать достаточно уникальное имя. Доступ к текущему контексту осуществляется с помощью flask._app_ctx_stack.top.