Non-global middleware in Django
在Django中,有一个设置文件,用于定义要在每个请求上运行的中间件。 此中间件设置是全局的。 有没有一种方法可以针对每个视图指定一组中间件? 我想让特定的URL使用一组不同于全局集的中间件。
您需要
1 2 3 4 5 | from django.utils.decorators import decorator_from_middleware @decorator_from_middleware(MyMiddleware) def view_function(request): #blah blah |
它不适用于URL,但可以按视图使用,因此您可以对其效果进行细粒度的控制。
对于这个问题,我有一个真正的解决方案。警告;这有点骇人听闻。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | """ 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 |
编辑:删除了两次运行该视图的先前版本。
这是我最近用来解决您在对Ned的答案的评论中提出的方案的一种解决方案...
它假定:
A)这是一种自定义中间件,或者您可以使用自己的中间件类对其进行扩展/包装
B)您的逻辑可以等到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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. |
可能有一种方法可以进一步推广这种模式,但这可以很好地实现我的目标。
为了回答您的更一般的问题,我认为Django库中没有任何东西可以帮助您解决当前问题。如果django-users邮件列表尚未在此处解决,它将是一个很好的主题。
您可以使用process_view方法,该方法在调用视图函数之前被调用。在process_view中,您可以检查-此视图是否需要这种中间件拦截。
我能找到的最好的方法就是使用request.path_info.startswith('...')通过仅返回请求来跳过中间件。现在,您可以仅为跳过而创建中间件,然后继承该中间件。也许您可以做一些更简单的事情,然后将该列表保存在settings.py中,然后跳过所有这些内容。如果我有任何错误,请告诉我。
在中间件的包装器中对
我认为这是从中间件中排除视图的简便方法
1 2 3 4 5 6 7 8 9 | 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" |
Django urlmiddleware允许仅将中间件应用于映射到特定url的视图。