在Django中间件中访问当前视图类实例
问题: 我试图访问中间件层中视图实例的属性 例如,给定如下基于类的视图:在Django中间件中访问当前视图类实例,django,django-class-based-views,django-middleware,Django,Django Class Based Views,Django Middleware,问题: 我试图访问中间件层中视图实例的属性 例如,给定如下基于类的视图: # views.py class MyView(View): my_attribute = 'something' # middleware.py def process_view(self, request, view_func, view_args, view_kwargs): my_attribute = request.view.my_attribute 我希望能够通过如下操作在中间件中处理my
# views.py
class MyView(View):
my_attribute = 'something'
# middleware.py
def process_view(self, request, view_func, view_args, view_kwargs):
my_attribute = request.view.my_attribute
我希望能够通过如下操作在中间件中处理my_属性
:
# views.py
class MyView(View):
my_attribute = 'something'
# middleware.py
def process_view(self, request, view_func, view_args, view_kwargs):
my_attribute = request.view.my_attribute
当然,这不起作用,因为Django不通过请求对象公开视图实例。有没有办法实现这一目标
谢谢
我的第一次尝试: 我最初认为
process\u view()
方法可能是实现这一点的好地方。不幸的是,它收到的view\u func
参数包含一个函数--MyView.as\u view()
--而不是视图实例本身。从:
处理视图(self、request、view\u func、view\u args、view\u kwargs)
…view_func是Django即将使用的Python函数。(这是实际的功能
对象,而不是作为字符串的函数名。)
我的第二次尝试: 视图实例的句柄可以在
process\u template\u response()
方法中找到,但这相当麻烦,而且,在任何情况下,我都希望能够在中间件堆栈的早期使用my\u属性。但这确实有效:
def process_template_response(self, request, response):
my_attribute = response.context_data['view'].my_attribute
如果它依赖于视图,那么它可能是该视图的混合体。如果您正在执行类似于依赖于活动视图的菜单的操作,我会反向查找当前URL名称:
没有内置的方法可以做到这一点,但这里有一个django用户邮件列表上的友好用户提供给我的解决方案。我在这里转载他的建议,以防其他人也这么做
这在以下情况下非常有用:
您希望在中间件中标识当前视图的属性并相应地执行处理,以及李>
出于各种原因,您不希望使用mixin或decorator来实现类似的结果
这将检查传递给process\u view()
中间件挂钩的view\u 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\u 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
另一种解决方案是创建新的视图类:
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框架()使用decorator,有很多方法可以实现所需的行为
1。如果您只想为中间件标记一个类来执行某些操作
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
2。如果要将视图中不需要的某些数据传递给中间件
from django.utils.decorators import classonlymethod
def tell_middleware(**kwargs):
def wrapper(class_view):
def as_view(cls, **initkwargs):
view = super(cls, cls).as_view(**initkwargs)
for k, v in kwargs.items():
setattr(view, k, v)
return view
return type(class_view.__name__, (class_view,), {
'as_view': classonlymethod(as_view),
})
return wrapper
@tell_middleware(my_attribute='something')
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):
my_attribute = getattr(view_func, 'my_attribute', 'default value')
if my_attribute == 'something':
# Do something
3。如果要向中间件公开某些视图属性
from django.utils.decorators import classonlymethod
def expose_to_middleware(*args):
def wrapper(class_view):
def as_view(cls, **initkwargs):
view = super(cls, cls).as_view(**initkwargs)
for attr in args:
setattr(view, attr, getattr(class_view, attr)
return view
return type(class_view.__name__, (class_view,), {
'as_view': classonlymethod(as_view),
})
return wrapper
@expose_to_middleware('my_attribute', 'my_other_attribute')
class MyView(View):
my_attribute = 'something'
my_other_attribute = 'else'
unexposed_attribute = 'foobar'
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):
my_attribute = getattr(view_func, 'my_attribute', 'default value')
if my_attribute == 'something':
# Do something
您试图解决的问题是什么?@burhan khalid:目标是根据视图属性的值在模板上下文中放置一些数据。我会使用上下文处理器来实现这一点,但也没有找到在上下文处理器中访问视图实例的方法。我目前的方法是使用一个mixin来覆盖get\u context\u data()
。这就完成了任务,但是每个请求都需要这个功能,所以我不想在应用程序的每个视图中都继承mixin。我还可以想到许多其他应用程序。仅举一个例子:处理视图访问控制的简单方法。我知道还有其他处理访问控制的方法,但这似乎是一种特别简单的方法,我想知道这是否可行。在某些情况下,这些绝对是潜在的解决方法。但是mixin必须在每个视图的继承层次结构中声明,如果您在任何地方都需要mixin,这可能会成为一个问题。这种情况不是由中间件更好地处理吗?如果路径通过request.path\u info
可用,为什么不让视图实例本身在request.view
中可用?更令人惊讶的是:视图实例在模板上下文中可用:我可以通过{{view.my_attribute}}
简单地获取视图属性。。。但要处理它,我需要使用一个模板标记。奇怪。很抱歉相切,但是能够直接使用视图实例不是对基于类的视图的一个很好的扩展吗?它可以让您全面地完成一些事情,而这些事情目前只能通过mixin逐个完成。或者使用decorator,这对于初学者来说是一个相当难访问的特性。在任何情况下,在模板中公开视图实例,而不是通过请求对象,似乎有点愚蠢。但我也可能在这里遗漏了一些根本性的东西