How to set up custom middleware in Django
First: The path structure
If you don't have it you need to create the middleware folder within your app following the structure:
yourproject/yourapp/middleware
The folder middleware should be placed in the same folder as settings.py, urls, templates...
Important: Don't forget to create the init.py empty file inside the middleware folder so your app recognizes this folder
Second: Create the middleware
Now we should create a file for our custom middleware, in this example let's suppose we want a middleware that filter the users based on their IP, we create a file called filter_ip_middleware.py inside the middleware folder with this code:
class FilterIPMiddleware(object):
# Check if client IP is allowed
def process_request(self, request):
allowed_ips = ['192.168.1.1', '123.123.123.123', etc...] # Authorized ip's
ip = request.META.get('REMOTE_ADDR') # Get client IP
if ip not in allowed_ips:
raise Http403 # If user is not allowed raise Error
# If IP is allowed we don't do anything
return None
Third: Add the middleware in our 'settings.py'
We need to look for:
-
MIDDLEWARE_CLASSES
(django < 1.10) -
MIDDLEWARE
(django >= 1.10)
Inside the settings.py we need to add our middleware (Add it in the last position). It should look like:
MIDDLEWARE = ( # Before Django 1.10 the setting name was 'MIDDLEWARE_CLASSES'
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# Above are django standard middlewares
# Now we add here our custom middleware
'yourapp.middleware.filter_ip_middleware.FilterIPMiddleware'
)
Done! Now every request from every client will call your custom middleware and process your custom code!
Writing middleware in Django>=1.10
Since Django 1.10, a middleware class must accept a get_response
argument in its __init__()
method and provide a __call__()
method. Although this can be achieved by using the django.utils.deprecation.MiddlewareMixin
when defining a middleware class (as shown in the answer by W.Perrin), creating a class-based middleware in the currently supported versions of Django looks like this:
class CustomMiddleware(object):
def __init__(self, get_response):
"""
One-time configuration and initialisation.
"""
self.get_response = get_response
def __call__(self, request):
"""
Code to be executed for each request before the view (and later
middleware) are called.
"""
response = self.get_response(request)
return response
def process_view(self, request, view_func, view_args, view_kwargs):
"""
Called just before Django calls the view.
"""
return None
def process_exception(self, request, exception):
"""
Called when a view raises an exception.
"""
return None
def process_template_response(self, request, response):
"""
Called just after the view has finished executing.
"""
return response
The process_view()
, process_exception()
and process_template_response()
are special hooks, called by Django when processing the middleware, you may define in your middleware class. In the example above, the implemented hooks will do nothing special expect for making sure that Django will call the next middleware to further process the response/request.
Activating middleware
To activate the middleware component, add it to the MIDDLEWARE
list in your Django settings.
MIDDLEWARE = [
# Default Django 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',
# Add your custom middleware
'path.to.your.middleware.CustomMiddleware',
]
Just two steps. It works for me with django2.1
.
1.Create your own Middleware class.
There is a good demo from official manual.
https://docs.djangoproject.com/en/2.1/ref/request-response/#django.http.HttpRequest.get_host
from django.utils.deprecation import MiddlewareMixin
class MultipleProxyMiddleware(MiddlewareMixin):
FORWARDED_FOR_FIELDS = [
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED_HOST',
'HTTP_X_FORWARDED_SERVER',
]
def process_request(self, request):
"""
Rewrites the proxy headers so that only the most
recent proxy is used.
"""
for field in self.FORWARDED_FOR_FIELDS:
if field in request.META:
if ',' in request.META[field]:
parts = request.META[field].split(',')
request.META[field] = parts[-1].strip()
2.Reference your Middleware class in the MIDDLEWARE
list of your project setting.py
file.
The rule for Middleware reference is the path to your class from the root directory of your project.
For example, in a project named mysite
,the tree is as follow.
├── mysite
│ ├── manage.py
│ ├── mysite
│ │ ├── __init__.py
│ │ ├── middleware.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
We just add our Middleware class MultipleProxyMiddleware
in the middleware.py
file. We get the following reference name.
MIDDLEWARE = [
'mysite.middleware.MultipleProxyMiddleware',
...
]