Контекст приложения Flask

Добавлено в версии 0.9.

Одно из проектных решений Flask заключается в том, что есть два разных “состояния”, в которых выполняется код. Состояние настройки приложения, которое подразумевается на уровне модуля. Оно наступает в момент, когда создаётся экземпляр объекта Flask, и заканчивается, когда поступает первый запрос. Пока приложение находится в этом состоянии, верно следующее:

  • программист может безопасно менять объект приложения.
  • запросы ещё не обрабатывались.
  • у вас имеется ссылка на объект приложения, чтобы изменить его, нет необходимости пользоваться каким-либо посредником для того, чтобы получить ссылку на созданный или изменяемый объект приложения.

Напротив, во время обработки запроса верны следующие правила:

  • пока активен запрос, объекты локального контекста (flask.request и другие) указывают на текущий запрос.
  • любой код может в любое время может заполучить эти объекты.

Есть и третье состояние, которое располагается между ними. Иногда можно работать с приложением так же, как и во время обработки запроса, просто в этот момент нет активного запроса. Например, вы можете работать с интерактивной оболочкой Python и взаимодействовать с приложением или запустить приложение из командной строки.

Контекст приложения - это то, чем управляет локальный контекст current_app.

Назначение контекста приложения

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

Каким образом код находит “правильное” приложение? В прошлом мы рекомендовали явную передачу приложений, но появились проблемы с библиотеками, которые не были спроектированы с учётом этого.

Обходной путь решения этой проблемы заключался в том, чтобы использовать посредника current_app, привязанного ссылкой к текущему запросу приложения. Но поскольку создание такого контекста запроса является не оправданно дорогостоящим в случае отсутствия запроса, был введён контекст приложения.

Создание контекста приложения

Для создания контекста приложения есть два способа. Первый из них - неявный: когда поступает контекст запроса, при необходимости также создаётся и контекст приложения. В результате вы можете игнорировать существование контекста приложения до тех пор, пока он вам не понадобится.

Второй способ - это явное создание контекста при помощи метода app_context():

from flask import Flask, current_app

app = Flask(__name__)
with app.app_context():
    # within this block, current_app points to app.
    print current_app.name

Контекст приложения также используется функцией url_for() в случае, если было настроено значение параметра конфигурации SERVER_NAME. Это позволяет вам генерировать URL’ы даже при отсутствии запроса.

Локальность контекста

Контекст приложения создаётся и уничтожается при необходимости. Он никогда не перемещается между потоками и не является общим для разных запросов. Поэтому - это идеальное место для хранения информации о подключении к базе данных и т.п. Внутренний объект стека называется flask._app_ctx_stack. Расширения могут хранить дополнительную информацию на самом верхнем уровне, если предполагается, что они выбрали достаточно уникальное имя и если они помещают свою информацию сюда, а не в объект flask.g, который зарезервирован для пользовательского кода.

За дополнительной информацией по теме обратитесь к разделу extension-dev.

Использование контекста

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

Наиболее распространённым использованием является разделение управления ресурсами на две части:

  1. неявное кэширование ресурсов в контексте.
  2. освобождение ресурса, основанное на демонтировании контекста.

В обычном случае, должна присутствовать функция get_X(), которая создаёт ресурс X, если он ещё не существует, и, если это не так, возвращает тот же самый ресурс, а также функция teardown_X(), которая регистрирует обработчик демонтирования.

Вот пример соединения с базой данных:

import sqlite3
from flask import g

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = connect_to_database()
    return db

@app.teardown_appcontext
def teardown_db(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

Соединение будет установлено, когда get_db() вызывается в первый раз. Для того, чтобы сделать это неявно, можно использовать класс LocalProxy:

from werkzeug.local import LocalProxy
db = LocalProxy(get_db)

С использованием этого способа пользователь может иметь прямой доступ к db, которая сама внутри себя вызовет get_db().

Оригинал этой страницы