首页 文章

访问Django中间件中的当前视图类实例

提问于
浏览
6

Question:

我正在尝试访问中间件层中的视图实例的属性 .

例如,给定一个基于类的视图,如下所示:

# views.py
class MyView(View):
    my_attribute = 'something'

我希望能够通过这样的方式在中间件中处理 my_attribute

# middleware.py
def process_view(self, request, view_func, view_args, view_kwargs):
    my_attribute = request.view.my_attribute

当然,这不起作用,因为Django不会通过请求对象公开视图实例 . 有没有办法实现这一目标?

谢谢!


My first attempt:

我最初认为 process_view() 方法可能是一个很好的地方 . 不幸的是,它收到的 view_func 参数包含一个函数 - MyView.as_view() 的输出 - 而不是视图实例本身 . 来自Django docs

process_view(self,request,view_func,view_args,view_kwargs)... view_func是Django即将使用的Python函数 . (它是实际的函数对象,而不是函数的名称作为字符串 . )...


My second attempt:

process_template_response() 方法中提供了视图实例的句柄,但它希望能够在中间件堆栈的早期点使用 my_attribute . 但这确实有效:

def process_template_response(self, request, response):
    my_attribute = response.context_data['view'].my_attribute

3 回答

  • 0

    没有内置的方法可以做到这一点,但这是一个由django-users邮件列表上的善良用户给我的解决方案 . 我在这里重新提出他的建议,以防其他人试图做同样的事情 .

    这有用:

    • 您想要识别中间件中当前视图的属性并相应地执行处理,并且;

    • 由于各种原因你不想使用mixins或decorator来完成类似的结果 .

    这将检查传递给 process_view() 中间件钩子的 view_func 对象,并确定并导入相应的视图类 .

    # middleware.py
    from myutils import get_class
    
    def process_view(self, request, view_func, view_args, view_kwargs):
            view = get_class(view_func.__module__, view_func.__name__)
            view.my_attribute
    

    然后你的 get_class() 定义:

    # myutils.py
    from django.utils import importlib
    
    def get_class(module_name, cls_name):
        try:
            module = importlib.import_module(module_name)
        except ImportError:
            raise ImportError('Invalid class path: {}'.format(module_name))
        try:
            cls = getattr(module, cls_name)
        except AttributeError:
            raise ImportError('Invalid class name: {}'.format(cls_name))
        else:
            return cls
    
  • 1

    另一种解决方案可能是创建一个新的View类:

    from django.views.generic.base import View
    class AddClassView(View):
        @classonlymethod
        def as_view(cls, **initkwargs):
            view = super(AddClassView, cls).as_view(**initkwargs)
            view.cls = cls
            return view
    

    并在基于类的视图中使用它:

    # views.py
    class MyView(AddClassView):
        my_attribute = 'something'
    

    然后在中间件中执行以下操作:

    # middleware.py
    def process_view(self, request, view_func, view_args, view_kwargs):
        view_func.cls.my_attribute  # 'something'
    

    此方法用于 Django REST Frameworkhttps://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/views.py#L94-L104

  • 3

    如果它取决于视图,它可能应该是该视图的混合 . 如果您正在执行类似于依赖于活动视图的菜单,我会反向查找当前URL名称:

    see a previous answer about using URL name lookup of the current URL

相关问题