title: How to Properly Short-Circuit Middleware in Django?
body: <p><strong>CONTEXT:</strong></p>
  
  <p>I am working on a Django 1.10/Python2.7 app with legacy stuff, and I am preparing part of it to pay some tech debt in near future. For that I need to put some logic on the chain of middleware used in the app to by-pass a whole set of layers underneath the Django ones if the URL being requested is to hit the API new app (<code>/api</code> routes).</p>
  
  <p>My idea was to introduce a new middleware in between the Django ones and the custom ones of the project (commented as "Custom middlewares" below as an example of what the proj has - in total about 8 middlewares, some of which make dozens of calls to DB and I don't know yet the implications of removing them or turning them into decorators for requests/views that need them). </p>
  
  <p>That intermediary middleware would short-circuit all the ones below it on <code>MIDDLEWARE</code> if the url starts with <code>/api</code>.</p>
  
  <p>I tried short-circuiting the Middleware chain in Django as they say in documentation but it is not working for me.</p>
  
  <p><strong>HOW I GOT IT WORKING (but not ideal):</strong></p>
  
  <p>The way I got it working was by doing this (which is not what they say in the documentation):</p>
  
  <p>This is the pre-existing <code>MIDDLEWARE</code> chain in <code>settings.py</code> in project:</p>
  
  <pre class="lang-py prettyprint-override"><code>(...)
  MIDDLEWARE = (
      'debug_toolbar.middleware.DebugToolbarMiddleware',
      'django.contrib.sessions.middleware.SessionMiddleware',
      'django.middleware.common.CommonMiddleware',
      'django.middleware.csrf.CsrfViewMiddleware',
      'django.contrib.auth.middleware.AuthenticationMiddleware',
      'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
      'django.middleware.security.SecurityMiddleware',
  
      'app2.middleware.PreExisting1Middleware',                   # Custom middlewares
      'app3.middleware.PreExisting2Middleware',                   # Custom middlewares
  )
  (...)
  </code></pre>
  
  <p>I added new <code>settings.py</code> key with:</p>
  
  <pre class="lang-py prettyprint-override"><code>SHORTCIRCUIT_MIDDLWARES_IF_URL_PATTERNS_IN = (r'^/api', )
  </code></pre>
  
  <p>To avoid applying <code>PreExisting1Middleware</code>, <code>PreExisting2Middleware</code> for URL routes starting with <code>/api</code> I created a base Middleware class as such:</p>
  
  <pre class="lang-py prettyprint-override"><code>import re
  
  from django.conf import settings
  from django.core.exceptions import ImproperlyConfigured
  from django.utils.deprecation import MiddlewareMixin
  
  
  class ShortCircuitMiddlewareMixin(MiddlewareMixin):
      def __call__(self, request):
          # Code to be executed for each request before the view (and later middleware) are called.
          response = None
          if hasattr(self, 'process_request') and self.should_middleware_be_applied(request):
              response = self.process_request(request)
          if not response:
              response = self.get_response(request)
          if hasattr(self, 'process_response') and self.should_middleware_be_applied(request):
              response = self.process_response(request, response)
          return response
  
      def should_middleware_be_applied(self, request):
          short_patterns = getattr(settings, 'SHORTCIRCUIT_MIDDLWARES_IF_URL_PATTERNS_IN', [])
          if hasattr(short_patterns, '__iter__'):
              if any(re.match(pattern, request.path) for pattern in short_patterns):
                  print('\nShort-circuiting the middleware: {}'.format(self.__class__.__name__))
                  return False
          else:
              raise ImproperlyConfigured(
                  "SHORTCIRCUIT_MIDDLWARES_IF_URL_PATTERNS_IN must be an iterable, got '{}'".format(short_patterns))
          return True
  </code></pre>
  
  <p>Then I use it as a base class for the middlewares <code>PreExisting1Middleware</code> and <code>PreExisting2Middleware</code>, that way, they get short-circuited if said url condition holds true.</p>
  
  <pre class="lang-py prettyprint-override"><code>Class PreExisting1Middleware(ShortCircuitMiddlewareMixin):
      def process_request(self, request):
          print('\nprocessing...')
          (...)
  
  Class PreExisting2Middleware(ShortCircuitMiddlewareMixin):
      def process_request(self, request):
          (...)
  </code></pre>
  
  <p>This works just fine, and I get a nice message on shell saying which middlewares were by-passed that can/should be logged if needed as well.</p>
  
  <p>Now, on to the question....</p>
  
  <p><strong>MY QUESTION:</strong></p>
  
  <p>Any idea on how to do it by using the right logic in the <code>__call__</code> method below and the MIDDLEWARE config below?</p>
  
  <pre class="lang-py prettyprint-override"><code>class ConditionallyShortcircuitChainMiddleware(object):
      def __init__(self, get_response):
          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)
  
          # Code to be executed for each request/response after
          # the view is called.
  
          return response
  </code></pre>
  
  <pre class="lang-py prettyprint-override"><code>(...)
  MIDDLEWARE = (
      'debug_toolbar.middleware.DebugToolbarMiddleware',
      'django.contrib.sessions.middleware.SessionMiddleware',
      'django.middleware.common.CommonMiddleware',
      'django.middleware.csrf.CsrfViewMiddleware',
      'django.contrib.auth.middleware.AuthenticationMiddleware',
      'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
      'django.middleware.security.SecurityMiddleware',
  
      'app1.middleware.ConditionallyShortcircuitChainMiddleware', # My new middleware
      'app2.middleware.PreExisting1Middleware',                   # Custom
      'app3.middleware.PreExisting2Middleware',                   # Custom
  )
  (...)
  </code></pre>
  
  <p>Relevant info from docs:
  See <a href="https://docs.djangoproject.com/en/2.2/topics/http/middleware/#middleware-order-and-layering" rel="nofollow noreferrer">here</a></p>
  
  <blockquote>
    <p><strong>Middleware order and layering</strong></p>
    
    <p>During the request phase, before calling the view, Django applies
    middleware in the order it’s defined in MIDDLEWARE, top-down.</p>
    
    <p>You can think of it like an onion: each middleware class is a “layer”
    that wraps the view, which is in the core of the onion. If the request
    passes through all the layers of the onion (each one calls
    get_response to pass the request in to the next layer), all the way to
    the view at the core, the response will then pass through every layer
    (in reverse order) on the way back out.</p>
    
    <p>If one of the layers decides to short-circuit and return a response
    without ever calling its get_response, none of the layers of the onion
    inside that layer (including the view) will see the request or the
    response. The response will only return through the same layers that
    the request passed in through.</p>
  </blockquote>