问题:
我正在尝试访问中间件层中的视图实例的属性。
例如,给定一个基于类的视图:
# 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不会通过请求对象公开视图实例。有没有办法实现这一目标?
谢谢!
我的第一次尝试:
我最初认为process_view()
方法可能是一个很好的地方。不幸的是,它收到的view_func
参数包含一个函数 - MyView.as_view()
的输出 - 而不是视图实例本身。来自Django docs:
process_view(self,request,view_func,view_args,view_kwargs)
... view_func是Django即将使用的Python函数。 (这是实际的功能 对象,而不是函数的名称作为字符串。)...
我的第二次尝试:
process_template_response()
方法提供了视图实例的句柄,但它非常尴尬,而且,无论如何,我希望能够在之前的某个时间点使用my_attribute
。中间件堆栈。但这确实有效:
def process_template_response(self, request, response):
my_attribute = response.context_data['view'].my_attribute
答案 0 :(得分:3)
没有内置的方法可以做到这一点,但这是一个由django-users邮件列表上的善良用户给我的解决方案。我在这里重新提出他的建议,以防其他人试图做同样的事情。
如果符合以下条件,这非常有用:
这将检查传递给view_func
中间件钩子的process_view()
对象,并确定并导入相应的视图类。
# 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 :(得分: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 Framework
(https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/views.py#L94-L104)
答案 2 :(得分:0)
如果它取决于视图,它可能应该是该视图的混合。如果您正在执行类似于依赖于活动视图的菜单,我会反向查找当前URL名称:
see a previous answer about using URL name lookup of the current URL
答案 3 :(得分:0)
使用装饰器,有很多方法可以实现所需的行为。
1。如果您只想标记一个中间件类来做某事
onChange
2。如果您要将一些不需要的数据传递给中间件,
Field
3。如果您想向中间件公开一些视图属性
from django.utils.decorators import classonlymethod
def special_marker(class_view):
def as_view(cls, **initkwargs):
view = super(cls, cls).as_view(**initkwargs)
view.special_marker = True
return view
return type(class_view.__name__, (class_view,), {
'as_view': classonlymethod(as_view),
})
@special_marker
class MyView(View):
pass
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_view(self, request, view_func, view_args, view_kwargs):
special_marker = getattr(view_func, 'special_marker', False)
if special_marker:
# Do something