OverIQ.com

Contexts in Flask

Last updated on July 27, 2020


Flask uses contexts to make temporarily certain variables globally accessible.

If you are coming from Django background, then you might have noticed that the view function in Flask doesn't accept request as the first argument. In Flask, we access data in the incoming request using the request object as follows:

1
2
3
4
5
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)

The above code may give you an impression that request is a global object, in truth it is not. If request had been a global object then in a multithreaded program our application wouldn't be able to distinguish between two simultaneous requests, since a multithreaded program shares all the variables among the threads. Flask uses something called Contexts to make certain variables act like global variables and when you access them you get access to the object for your current thread. In technical jargon, such variables are known as thread-locals.

According to the documentation Flask provides two contexts:

  1. Application Context.
  2. Request Context.

The Application context is used to store values which are generic to the application like database connection, configurations etc; whereas Request context is used to store values that are specific to each request.

The application context exposes objects like current_app and g. The current_app refers to the instance handling the request and g is used to temporarily store data during request handling. Once a value is set you can access it inside any view function. The data stored in g resets after every request.

Just like the application context, request context also exposes objects like request and session. As already discussed, the request object contains the information about the current web request and session is a dictionary-like object that is used to store values that persists between requests.

Flask activates (or pushes) application and request context when a request is received and removes them when the request is handled. When application context is pushed all the variables exposes by it becomes available to the thread. Similarly, when request context is pushed all the variables exposes by it becomes available to the thread. Inside the view functions, you have access to all the objects exposes by application and request context, so you don't have worry about whether application or request context is active or not. However, if you try to access these objects outside a view function or in a Python Shell you will get an error. The following shell session demonstrates this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
>>> 
>>> from flask import Flask, request, current_app
>>> 
>>> request.method   # get the 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.
>>>

The request.method returns the HTTP method used in the request but since there is no actual HTTP request, the request context is not active.

You will get a similar error if, you try to access an object exposed by the application context.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>>> 
>>> current_app.name  # get the name of the application
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.
>>>

To access objects exposed by the application/request context outside of the view function you have to create application/request context first.

We can create the application context using the app_context() method of the Flask instance.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>>>
>>> from main2 import app
>>> from flask import Flask, request, current_app
>>>
>>> app_context = app.app_context()
>>> app_context.push()
>>>
>>> current_app.name
'main2'
>>>
>>>

The preceding code can be simplified using the with statement as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>>
>>> from main2 import app
>>> from flask import Flask, request, current_app
>>>
>>> with app.app_context():
...    current_app.name
...
'main2'
>>>
>>>

The with statement is the preferred way of creating contexts.

Similarly, we can create the request context using the test_request_context() method of the Flask instance. The important point to remember is that whenever a request context is pushed application context is created if not already exists. The following shell session demonstrates how to create request context:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
>>>
>>> from main2 import app
>>> from flask import current_app, request
>>>
>>> with app.test_request_context('/products'):
...     request.path  # get the full path of the requested page without the domain name.
...     request.method
...     current_app.name
...
'/products'
'GET'
'main2'
>>>
>>>

The URL /products is arbitrarily chosen.

That's all you need to know about contexts in Flask.