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.