在Django中有一个设置文件,用于定义要在每个请求上运行的中间件。此中间件设置是全局的。有没有办法在每个视图的基础上指定一组中间件?我希望特定的URL使用一组与全局集不同的中间件。
答案 0 :(得分:39)
from django.utils.decorators import decorator_from_middleware
@decorator_from_middleware(MyMiddleware)
def view_function(request):
#blah blah
它不适用于网址,但它适用于每个视图,因此您可以对其效果进行细粒度控制。
答案 1 :(得分: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
编辑:删除了两次运行视图的先前版本。
答案 2 :(得分:5)
这是我最近用来解决你在对Ned的回答的评论中提出的场景的解决方案......
它假设:
A)这是一个自定义中间件或者您可以使用自己的中间件类扩展/包装的中间件
B)您的逻辑可以等到process_view
而不是process_request
,因为在process_view
中,您可以在解析后检查view_func
参数。 (或者您可以调整下面的代码以使用Ignacio指示的urlresolvers
。
# 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邮件列表来说,如果它还没有在那里解决,那将是一个很好的主题。
答案 3 :(得分:2)
您可以使用在调用view func之前调用的process_view方法。在process_view中,您可以检查 - 此视图是否需要此中间件拦截。
答案 4 :(得分:1)
在中间件的包装器中对request.path
使用django.core.urlresolvers.resolve()
以尝试查看视图是否在应用内,如果是,则跳过处理。
答案 5 :(得分:1)
我能找到的最好的事情是使用if request.path_info.startswith('...')通过返回请求来跳过中间件。现在,您可以仅为了跳过而创建中间件,然后继承它。也许你可以做一些更简单的事情,并在settings.py中保存该列表,然后跳过所有这些。如果我错了,请告诉我。
答案 6 :(得分:0)
Django urlmiddleware允许仅将中间件应用于映射到特定网址的视图。
答案 7 :(得分:0)
我认为这是从中间件中排除视图的简单方法
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"
答案 8 :(得分: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)