Non-global middleware in Django

前端 未结 8 972
生来不讨喜
生来不讨喜 2020-12-12 21:59

In Django there is a settings file that defines the middleware to be run on each request. This middleware setting is global. Is there a way to specify a set of middleware

相关标签:
8条回答
  • 2020-12-12 22:35

    The best thing I've been able to find is using if request.path_info.startswith('...') to skip over the middleware by just returning the request. Now, you could create middleware just for the sake of skipping and then inherit that. Maybe you could do something even simpler and save that list in your settings.py and then skip all those. If I'm wrong in any way, let me know.

    0 讨论(0)
  • 2020-12-12 22:40

    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.py
    EXCLUDE_FROM_MY_MIDDLEWARE = set('myapp.views.view_to_exclude', 
        'myapp.views.another_view_to_exclude')
    
    # some_middleware.py
    
    from django.conf import settings
    
    def 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.

    0 讨论(0)
  • 2020-12-12 22:40

    Django urlmiddleware allows to apply middleware only to views that are mapped to specific urls.

    0 讨论(0)
  • 2020-12-12 22:45

    I think this is the easy way to exclude a view from middleware

     from django.core.urlresolvers import resolve
     current_url = resolve(request.path_info).url_name
    
     if want to exclude url A,
    
     class your_middleware:
        def process_request(request):
            if not current_url == 'A':
                "here add your code"
    
    0 讨论(0)
  • 2020-12-12 22:46

    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):
    
    @shortcircuitmiddleware
    def 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 _shortcircuitmiddleware
    
    class 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.

    0 讨论(0)
  • 2020-12-12 22:48

    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.

    0 讨论(0)
提交回复
热议问题