Writing a custom middleware in Django to log slow responses

As mentioned in the Django official docs, Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.

Each middleware component is responsible for doing some specific function. For example, Django includes a middleware component called AuthenticationMiddleware, that associates users with requests using sessions.

The following example creates a custom middleware to log reponses which take more that 2 seconds to complete.

  1. Create a python package (a folder with __init__.py inside) named as middleware
  2. Create a file named, for instance, slow_api_log.py and a regular Python class in it like bellow:

To enable the custom middleware, just add the path to the file in the MIDDLEWARE list in settings.py.

MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
# ENABLE THE NEW MIDDLEWARE
"your_app.middleware.slow_api_log.APILogMiddleware",
]

The two required methods in all Django middleware class :

  • .- Used in all Python classes to bootstrap object instances. The method in Django middleware classes only gets called once, when the web server backing the Django application starts. The method in Django middleware must declare a input, which represents a reference to a prior middleware class response. The input is assigned to an instance variable -- also named -- which is later used in the main processing logic of the middleware class.
  • .- Used in all Python classes to call an object instance as a function. The method in Django middleware classes is called on every application request. The method declares a input which represents the same object used by view methods. The method goes through three phases:
  • Before view method call.- Once the method is triggered, you get the opportunity to alter the reference before it's passed to a view method. If you want to add or modify something in before it gets turned over to a view method, this is the phase to do it in.
  • Trigger view method call.- After you modify (or not) the original , you must turn over control to the view method in order for it to run. This phase is triggered when you pass to the reference you set in the method. This phase effectively says "I'm done modifying the , go ahead and turn it over to the view method so it can run".
  • Post view method call.- Once a view method finishes, the results are assigned to the reference in . In this phase, you have the opportunity to perform logic after a view method finishes. You exit this phase by simply returning the reference from the view method (i.e. ).

In summary, the execution process for a single middleware class is the following:

  1. method triggered (On server start-up).
  2. method triggered (On every request).
  3. If declared, method triggered.
  4. View method starts with statement in .
  5. If declared, method triggered when exception occurs in view.
  6. View method finishes.
  7. If declared, triggered when view returns .