Non-global middleware in Django Non-global middleware in Django python python

Non-global middleware in Django


You want decorator_from_middleware.

from django.utils.decorators import decorator_from_middleware@decorator_from_middleware(MyMiddleware)def view_function(request):    #blah blah

It doesn't apply to URLs, but it works per-view, so you can have fine-grained control over its effect.


I have a real solution for this issue. Warning; it's a little bit of a hack.

""" Allows short-curcuiting of ALL remaining middleware by attaching the@shortcircuitmiddleware decorator as the TOP LEVEL decorator of a view.Example settings.py: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',    # THIS MIDDLEWARE    'myapp.middleware.shortcircuit.ShortCircuitMiddleware',    # SOME OTHER MIDDLE WARE YOU WANT TO SKIP SOMETIMES    'myapp.middleware.package.MostOfTheTimeMiddleware',    # MORE MIDDLEWARE YOU WANT TO SKIP SOMETIMES HERE)Example view to exclude from MostOfTheTimeMiddleware (and any subsequent):@shortcircuitmiddlewaredef myview(request):    ..."""def shortcircuitmiddleware(f):    """ view decorator, the sole purpose to is 'rename' the function    '_shortcircuitmiddleware' """    def _shortcircuitmiddleware(*args, **kwargs):        return f(*args, **kwargs)    return _shortcircuitmiddlewareclass ShortCircuitMiddleware(object):    """ Middleware; looks for a view function named '_shortcircuitmiddleware'    and short-circuits. Relies on the fact that if you return an HttpResponse    from a view, it will short-circuit other middleware, see:    https://docs.djangoproject.com/en/dev/topics/http/middleware/#process-request     """    def process_view(self, request, view_func, view_args, view_kwargs):        if view_func.func_name == "_shortcircuitmiddleware":            return view_func(request, *view_args, **view_kwargs)        return None

Edit: removed previous version that ran the view twice.


Here's a solution I used recently to address the scenario you presented in a comment to Ned's answer...

It assumes that:

A) this is a custom middleware or one that you can extend/wrap with your own middleware class

B) your logic can wait until process_view instead of process_request, because in process_view you can inspect the view_func parameter after it's been resolved. (Or you can adjust the code below to use urlresolvers as indicated by Ignacio).

# settings.pyEXCLUDE_FROM_MY_MIDDLEWARE = set('myapp.views.view_to_exclude',     'myapp.views.another_view_to_exclude')# some_middleware.pyfrom django.conf import settingsdef process_view(self, request, view_func, view_args, view_kwargs):    # Get the view name as a string    view_name = '.'.join((view_func.__module__, view_func.__name__))    # If the view name is in our exclusion list, exit early    exclusion_set = getattr(settings, 'EXCLUDE_FROM_MY_MIDDLEWARE', set())    if view_name in exclusion_set:        return None    # ... middleware as normal ...    #    # Here you can also set a flag of some sort on the `request` object    # if you need to conditionally handle `process_response` as well.

There may be a way to generalize this pattern further, but this accomplished my goal fairly well.

To answer your more general question, I don't think there is anything in the Django libraries to help you out with this currently. Would be a good topic for the django-users mailing list if it hasn't already been addressed there.