Контекст приложения
Журнал изменений
Новая версия 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 даже при отсутствии запроса.
Если контекст запроса не был добавлен, и контекст приложения не был явно задан, будет поднято исключение RuntimeError.
RuntimeError: Working outside of application context.
Локальность контекста
Контекст приложения создаётся и уничтожается по мере необходимости. Он никогда не перемещается между потоками и не будет общим для запросов. Таким образом, он идеально подходит для хранения информации о подключении к базе данных и других данных. Внутренний объект стека называется flask._app_ctx_stack. Расширения могут свободно хранить дополнительную информацию на верхнем уровне, если они выбирают достаточно уникальное имя и должны поместить туда свою информацию вместо объекта flask.g, который зарезервирован для пользовательского кода.
Дополнительную информацию можно найти в Разработка расширений Flask.
Использование контекста
Контекст обычно используется для кэширования ресурсов, которые необходимо создавать для каждого запроса или случая использования. Например, соединения с базой данных предназначены для этого. При хранении чего-либо в контексте приложения следует выбирать уникальные имена, так как это место, где совместно работают приложения 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().
© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/0.12.x/appcontext/