Question:
I'm trying to access an attribute of the view instance in the middleware layer.
我正在尝试访问中间件层中的视图实例的属性。
For example, given a class-based view like this:
例如,给定一个基于类的视图,如下所示:
# views.py
class MyView(View):
my_attribute = 'something'
I'd love to be able to get a handle on my_attribute
in the middleware by doing something like this:
我希望能够通过这样的方式获得中间件中my_attribute的句柄:
# middleware.py
def process_view(self, request, view_func, view_args, view_kwargs):
my_attribute = request.view.my_attribute
Of course, this does not work because Django doesn't expose the view instance through the request object. Is there a way to get this accomplished?
当然,这不起作用,因为Django不会通过请求对象公开视图实例。有没有办法实现这一目标?
Thanks!
My first attempt:
我的第一次尝试:
I initially figured that the process_view()
method might be a good place to do this. Unfortunately, the view_func
argument it receives contains a function -- the output of MyView.as_view()
-- rather than the view instance itself. From the Django docs:
我最初认为process_view()方法可能是一个很好的地方。不幸的是,它接收的view_func参数包含一个函数 - MyView.as_view()的输出 - 而不是视图实例本身。来自Django文档:
process_view(self, request, view_func, view_args, view_kwargs)
process_view(self,request,view_func,view_args,view_kwargs)
...view_func is the Python function that Django is about to use. (It’s the actual function object, not the name of the function as a string.)...
... view_func是Django即将使用的Python函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)...
My second attempt:
我的第二次尝试:
A handle to the view instance is available in process_template_response()
method, but it's pretty awkward, and, in any case, I'd like to be able to work with my_attribute
at an earlier point in the middleware stack. But this does work:
process_template_response()方法中提供了视图实例的句柄,但它非常笨拙,而且,无论如何,我希望能够在中间件堆栈的早期阶段使用my_attribute。但这确实有效:
def process_template_response(self, request, response):
my_attribute = response.context_data['view'].my_attribute
3 个解决方案
#1
3
There is no built-in way to do this, but here is a solution given to me by a kindly user on the django-users mailing list. I'm reposting his suggestion here in case anyone else is trying to do the same thing.
没有内置的方法可以做到这一点,但这是一个由django-users邮件列表上的善良用户给我的解决方案。我在这里重新提出他的建议,以防其他人试图做同样的事情。
This is useful if:
这在以下情况下很有用
- you want to identify properties of the current view in your middleware and perform processing accordingly, and;
- for various reasons you don't want to use mixins or decorators to accomplish similar results.
您希望在中间件中识别当前视图的属性并相应地执行处理,并且;
由于各种原因,您不希望使用mixins或decorator来实现类似的结果。
This inspects the view_func
object passed to the process_view()
middleware hook and determines and imports the the appropriate view class.
这将检查传递给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
Then your get_class()
definition:
然后你的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
#2
1
Another solution could be to create a new View class:
另一种解决方案可能是创建一个新的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
And use this in your class based view:
并在基于类的视图中使用它:
# views.py
class MyView(AddClassView):
my_attribute = 'something'
Then you do the following in the middleware:
然后在中间件中执行以下操作:
# middleware.py
def process_view(self, request, view_func, view_args, view_kwargs):
view_func.cls.my_attribute # 'something'
This method is used in the Django REST Framework
(https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/views.py#L94-L104)
此方法用于Django REST框架(https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/views.py#L94-L104)
#3
0
If it depends on the view, it should probably be a mixin of that view. If you're doing something like a menu that depends on the active view, I'd do a reverse lookup of the current URL name:
如果它取决于视图,它可能应该是该视图的混合。如果您正在执行类似于依赖于活动视图的菜单,我会反向查找当前URL名称:
see a previous answer about using URL name lookup of the current URL
查看有关使用当前URL的URL名称查找的上一个答案
#1
3
There is no built-in way to do this, but here is a solution given to me by a kindly user on the django-users mailing list. I'm reposting his suggestion here in case anyone else is trying to do the same thing.
没有内置的方法可以做到这一点,但这是一个由django-users邮件列表上的善良用户给我的解决方案。我在这里重新提出他的建议,以防其他人试图做同样的事情。
This is useful if:
这在以下情况下很有用
- you want to identify properties of the current view in your middleware and perform processing accordingly, and;
- for various reasons you don't want to use mixins or decorators to accomplish similar results.
您希望在中间件中识别当前视图的属性并相应地执行处理,并且;
由于各种原因,您不希望使用mixins或decorator来实现类似的结果。
This inspects the view_func
object passed to the process_view()
middleware hook and determines and imports the the appropriate view class.
这将检查传递给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
Then your get_class()
definition:
然后你的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
#2
1
Another solution could be to create a new View class:
另一种解决方案可能是创建一个新的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
And use this in your class based view:
并在基于类的视图中使用它:
# views.py
class MyView(AddClassView):
my_attribute = 'something'
Then you do the following in the middleware:
然后在中间件中执行以下操作:
# middleware.py
def process_view(self, request, view_func, view_args, view_kwargs):
view_func.cls.my_attribute # 'something'
This method is used in the Django REST Framework
(https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/views.py#L94-L104)
此方法用于Django REST框架(https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/views.py#L94-L104)
#3
0
If it depends on the view, it should probably be a mixin of that view. If you're doing something like a menu that depends on the active view, I'd do a reverse lookup of the current URL name:
如果它取决于视图,它可能应该是该视图的混合。如果您正在执行类似于依赖于活动视图的菜单,我会反向查找当前URL名称:
see a previous answer about using URL name lookup of the current URL
查看有关使用当前URL的URL名称查找的上一个答案