Контекст приложения 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.
Наиболее распространённым использованием является разделение управления ресурсами на две части:
- неявное кэширование ресурсов в контексте.
- освобождение ресурса, основанное на демонтировании контекста.
В обычном случае, должна присутствовать функция 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()
.