Flask применяет концепцию контекстов для возможности временного размещения определенных глобальных переменных в общей области видимости.

Тем, кто знаком с Django, может показаться необычным, что метод представления во Flask не использует объект request в качестве первого аргумента. Во Flask данные запроса доступны через объект request, что может выглядеть так:

from flask import Flask, request

@app.route('/')
def requestdata():
    return "Hello! Your IP is {} and you are using {}: ".format(request.remote_addr,
                                                                request.user_agent)

Создается впечатление, что request - глобальный объект. Однако это не так. Если бы request был глобальным, то в многопоточной среде приложение не смогло бы разделить запросы. Переменные просто распределяются между всеми потоками. Во Flask это решается с помощью контекстов. Контексты позволяют отдельным переменным вести себя как глобальные. При обращении к ним пользователь в действительности взаимодействует с объектом в конкретном потоке. Технически такие переменные называются "внутрипоточными" или "локальными".

По документации Flask, существует два типа контекстов:

  1. Контекст приложения
  2. Контекст запроса

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

Из контекста приложения разработчики могут получить объекты вроде current_app и g. current_app указывает на экземпляр приложения, обрабатывающий запрос, а g используется для временного хранения данных на протяжении срока запроса. Доступ к данным g можно получить из любой функции представления, но после запроса они сбрасываются.

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

Когда Flask принимает запрос, он активирует оба контекста — приложения и запроса, а затем их удаляет после обработки запроса. Это позволяет переменным в этих контекстах стать доступными для выполнения в потоке запроса. Внутри функций представления это означает, что все объекты контекстов приложения и запроса доступны автоматически, что избавляет вас от беспокойства об их активации. Однако, если попытаться их использовать вне функции представления, например из консоли Python, это вызовет ошибку:

>>> 
from flask import Flask, request, current_app
>>> 
>>>  request.method # получение метода запроса
Traceback (most recent call last):
#...
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed an active HTTP request. Consult the documentation on testing for information about how to avoid this problem.
>>>

request.method должен возвратить HTTP-метод запроса, однако поскольку запроса в текущий момент нет, контекст запроса также не активен.

Подобная ошибка произойдет при попытке доступа к объекту, предоставляемому контекстом приложения:

>>> current_app.name # попытка получить название приложения
Traceback (most recent call last):
#...
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 a way. To solve
this set  up an application context with app.app_context(). See the documentation for more information.
>>>

Для получения доступа к объектам из контекстов приложения и запроса вне функций представлений необходимо сначала создать нужный контекст.

Контекст приложения можно создать, вызвав метод app_context() на экземпляре Flask.

>>> from main2 import app
>>> from flask import Flask, request, current_app
>>>
>>> app_context = app.app_context()
>>> app_context.push()
>>>
>>> current_app.name
'main2'

Этот код можно упростить, используя конструкцию with:

>>> from main2 import app
>>> from flask import request, current_app
>>>
>>>
>>> with app.app_context():
...     current_app.name
...
'main2'
>>>

Использование with — это лучший подход при создании контекстов.

Контекст запроса можно создавать через метод test_request_context() экземпляра Flask. Имейте в виду, что при активации контекста запроса контекст приложения создает автоматически, если ранее не существовал. Ниже представлен пример создания контекста запроса:

>>> from main2 import app
>>> from flask import request, current_app
>>>
>>>
>>> with app.test_request_context('/products'):
...     request.path  # Получение пути к запрашиваемой странице
...     request.method
...     current_app.name
...
'/products'
'GET'
'main2'
>>>

Адрес /products выбран произвольно.
Это основная информация, которую стоит знать о контекстах во Flask.

Вопросы для самопроверки:

  1. Какую концепцию использует Flask для временного размещения определенных глобальных переменных?
  2. Почему объект request в Flask не является глобальным в многопоточной среде?
  3. Для чего используется контекст приложения?
  4. Для чего предназначен объект g?
  5. Какие ошибки возникают при попытке использования объектов контекста вне функции представления?