Question

I am trying to create middleware to optionally pass a kwarg to every view that meets a condition.

The problem is that I cannot find an example of how to set up the middleware. I have seen classes that override the method I want to, process_view:

Class CheckConditionMiddleware(object):  
    def process_view(self, request):  

        return None  

But where do I put this class? Do I create a middleware app and put this class inside of it and then reference it in settings.middleware?

Was it helpful?

Solution

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!

OTHER TIPS

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',  
     ...
]

First, middleware is actually the bridge between Httprequest and HttpResponse, it's normally globally, because it's the bridge, because the HttpRequest must walk the bridge to reach the server and walk the bridge back to the client with the HttpResponse. It's supercool, which means you can write a bunch of method to be run before the request hit the server,or after the request hit the server. Take the csrfmiddleware as an example, the request will first be judged by the middleware whether it's method is POST, if true, then middleware will compare the csrf_token it possessed with the token stored inside the server, this token is generated when you send the HTML with the form tag, because normally, client will only be able to send POST request through the form server directly send to the client, so server can use this to judge whether this POST is from the form server sent to you, and combined with authentication or authorization, decide whether to send the reqeust to the server or just object the request overall. So,when you write your own middleware, be clear about what you want to do with the request or response, do you want to add an element in the response? Like the messagemiddleware did, this new element can be seen as the context django view send or you want to add session, and check the session everytime the client make a request, with this mindset, follow some fixed format, like in this websitehttps://medium.com/scalereal/everything-you-need-to-know-about-middleware-in-django-2a3bd3853cd6.

It will be helpful in the case of When you know what type of Exception occurs in the views. From the above I have Created my own Custom class like

from .models import userDetails

class customMiddleware(object):

    def process_request(self,request):
        result=''
        users = userDetails.objects.all()
        print '-->',users ,'---From middleware calling ---'

        username=request.POST.get("username")
        salary = request.POST.get("salary")
        if salary:
            try:
                result = username+int(salary)
            except:
                print "Can't add"

It will be executed when the exception occur in the case of string and integer addition.

You can write Corresponding views for above middleware class

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top