48

在 Django 中有一个设置文件,它定义了要在每个请求上运行的中间件。此中间件设置是全局的。有没有办法在每个视图的基础上指定一组中间件?我想让特定的 url 使用一组不同于全局集的中间件。

4

9 回答 9

56

你想要decorator_from_middleware

from django.utils.decorators import decorator_from_middleware

@decorator_from_middleware(MyMiddleware)
def view_function(request):
    #blah blah

它不适用于 URL,但它适用于每个视图,因此您可以对其效果进行细粒度控制。

于 2010-05-26T22:03:51.307 回答
7

对于这个问题,我有一个真正的解决方案。警告; 这有点像黑客。

""" 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

编辑:删除了运行视图两次的先前版本。

于 2011-08-31T17:09:25.733 回答
6

这是我最近用来解决您在对 Ned 的回答的评论中提出的场景的解决方案......

它假设:

A)这是一个自定义中间件,或者您可以使用自己的中间件类扩展/包装的中间件

B)您的逻辑可以等到,process_view而不是process_request,因为您可以在解决参数后process_view检查参数。view_func(或者您可以调整下面的代码以urlresolvers按照 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.

可能有一种方法可以进一步概括这种模式,但这很好地实现了我的目标。

为了回答您更一般的问题,我认为 Django 库中目前没有任何东西可以帮助您解决这个问题。如果 django-users 邮件列表还没有解决的话,这将是一个很好的话题。

于 2010-05-26T22:47:51.693 回答
2

您可以使用 process_view 方法,该方法在调用视图函数之前调用。在 process_view 你可以检查——如果这个视图需要这个中间件拦截。

于 2015-10-13T14:03:41.550 回答
1

我能找到的最好的事情是使用 if request.path_info.startswith('...') 通过返回请求来跳过中间件。现在,您可以创建中间件只是为了跳过然后继承它。也许您可以做一些更简单的事情并将该列表保存在您的 settings.py 中,然后跳过所有这些。如果我有任何错误,请告诉我。

于 2013-08-22T22:07:34.500 回答
1

在中间件的包装器中使用django.core.urlresolvers.resolve()反对request.path来尝试查看视图是否在应用程序内,如果是则跳过处理。

于 2010-05-26T22:14:46.723 回答
1

我认为这是从中间件中排除视图的简单方法

 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"
于 2018-01-23T07:01:22.663 回答
0

Django urlmiddleware允许仅将中间件应用于映射到特定 url 的视图。

于 2012-12-11T18:49:42.223 回答
0
#settings.py
EXCLUDE_FROM_MY_MIDDLEWARE =set({'custom_app.views.About'})

#middlware.py
from django.conf import settings

class SimpleMiddleware(object):

     def __init__(self,get_response):
          self.get_response=get_response
          
     
     def __call__(self,request):
          
          response = self.get_response(request)
          return response

     def process_view(self,request, view_func, view_args, view_kwargs):
         
          view_function='.'.join((view_func.__module__,view_func.__name__))
          exclusion_set=getattr(settings,'EXCLUDE_FROM_MY_MIDDLEWARE',set() )
          if view_function in exclusion_set:
               return None
          
          print("continue for others views")
          
     def process_exception(self,request, exception):
          return HttpResponse(exception)
于 2021-02-12T07:37:49.877 回答