Understanding Django Middleware and Create Own Middleware with a Use Case
Django, the popular Python web framework, offers developers a powerful toolset to build robust and scalable web applications. Among its many features, middleware plays an important role in shaping the request/response processing flow. In this blog post, we will dive into the Django middleware, exploring its definition and methods, how it works, and the practical use cases where it can catch specific exception when occurs an error in your web application.
1. What is Django Middleware?
Middleware in Django refers to a set of components that intercept and process HTTP requests and responses before they reach the view or after the view has processed the response. It acts as a gatekeeper, allowing developers to execute custom functionalities during the request-response lifecycle. Middleware functions as a chain, where each component can modify or halt the flow of data, granting developers granular control over the application’s behavior.
2. How Does Middleware Work?
When a request hits a Django application, it passes through a stack of middleware components in the order specified in the MIDDLEWARE
settings. Each middleware can inspect the request, perform tasks like authentication, data manipulation, or logging, and then pass the request to the next middleware. While a middleware is defined in settings.py order of middleware is very important. After the view processes the request and generates a response, the response traverses back through the middleware stack in reverse order, allowing them to inspect or modify the response.
3. Django Built-in Middlewares
Django ships with several built-in middleware to handle common tasks like authentication, security, and content-type negotiation. Some well-kno built-in middleware includes:
- AuthenticationMiddleware
- SessionMiddleware
- CsrfViewMiddleware
- GZipMiddleware
- CommonMiddleware
You can visit the django official documentation for further information. https://docs.djangoproject.com/en/4.2/topics/http/middleware/
4. Creating Custom Middleware
Developers can craft their middleware to cater to specific application needs. We will create our own custom middleware as we needs. However, we need to understand django’s middleware methods and its meaning.
__init__(self, get_response)
The __init__
method is the constructor for the middleware class. It is called when the middleware is initialized or when the server starts. This means it is called ionly once, when the web server starts. You can use here different purposes like creating other services client.
__call__(self, request)
The __call__
method is called for each incoming HTTP request. It processes the request and decides what to do with it, such as processing it further, altering the request, or stopping processing altogether. Generally, main part of our middleware would be here for our processes.
process_view
(self, request, view_func, view_args, view_kwargs)
process_view()
is called just before Django calls the view.
process_exception(self,
request, response)
This method is used to handle exceptions that occur during the processing of an HTTP request. It provides a way to intercept and handle exceptions raised by views or other middleware before they reach the Django framework’s default exception handling.
process_template_response
(request, response)
This method is used to intercept and modify the response generated by a view before it is rendered using a template. This provides an opportunity to add or manipulate data in the context, customize the template, or perform other actions that involve the rendering process.
Use Case:
“I want to catch AttributeError and handle it when it occurs in my django project.”
from django.utils.translation import gettext as _
from django.http import JsonResponse
import logging
import traceback
class CustomMiddleware:
def __init__(self, get_response):
# One-time configuration and initialization.
self.logger = logging.getLogger(__name__)
self.get_response = get_response
def __call__(self, request):
translation.activate(request.language)
response = self.get_response(request)
response.headers['Locale'] = request.language
return response
def process_exception(self, request, exception):
error_type = type(exception)
if AttributeErro == error_type:
self.logger.exception(exception, exc_info=True)
return JsonResponse(dict(success=False, message=_("Please provide corret values")))