Django 中的非全局中间件

发布于 2024-09-03 02:44:25 字数 100 浏览 11 评论 0原文

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

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 on a per-view basis? I want to have specific urls use a set of middleware different from the global set.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

二手情话 2024-09-10 02:44:25

您想要 decorator_from_middleware

from django.utils.decorators import decorator_from_middleware

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

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

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.

风情万种。 2024-09-10 02:44:25

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

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

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

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.

╰◇生如夏花灿烂 2024-09-10 02:44:25

这是我最近用来解决您在对 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 邮件列表还没有解决这个问题,那么这将是一个很好的主题。

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.

四叶草在未来唯美盛开 2024-09-10 02:44:25

您可以使用 process_view 方法,该方法在调用视图函数之前调用。在 process_view 中,您可以检查 — 该视图是否需要此中间件拦截。

You can use process_view method, that is called before calling the view func. In process_view you can check — if this view requires this middleware interception.

哎呦我呸! 2024-09-10 02:44:25

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

(注:据我记得,我此时使用的是 Django 1.2)

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.

(Note: from what I remember, I was using Django 1.2 at this time)

像极了他 2024-09-10 02:44:25

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

Use django.core.urlresolvers.resolve() against request.path in a wrapper for the middleware to try to see if the view is within the app, and skip processing if so.

临走之时 2024-09-10 02:44:25

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

 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"

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"
攒一口袋星星 2024-09-10 02:44:25

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

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

负佳期 2024-09-10 02:44:25
#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)
#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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文