2013-12-21 137 views
6

問:訪問當前視圖類的實例在Django中間件

我試圖訪問視圖實例的屬性在中間件層。

例如,給出一個基於類的觀點是這樣的:

# 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(個體經營,要求,view_func,view_args,view_kwargs)

... view_func是Python函數,Django將要使用的。 (它的實際功能 對象,函數作爲字符串的不是名稱。)...


我的第二次嘗試:

的句柄查看實例可用process_template_response()方法,但它非常尷尬,並且無論如何,我希望能夠在中間件堆棧的早期階段與my_attribute一起使用。但這確實有效:

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

什麼是你正在試圖解決這個問題? –

+0

@ burhan-khalid:目標是根據視圖屬性的值在模板上下文中放置一些數據。我會用上下文處理器來做到這一點,但是還沒有找到在上下文處理器中訪問視圖實例的方法。我目前的做法是使用一個覆蓋'get_context_data()'的mixin。這可以完成工作,但是每個請求都需要這個功能,所以我想避免在應用程序的每個視圖中從mixin繼承。 – tino

+0

我也可以考慮一些其他的應用程序。只是一個例子:一個簡單的方法來處理視圖訪問控制。我知道還有其他處理訪問控制的方式,但這似乎是一種特別簡單的方法,我很想知道它是否可行。 – tino

回答

2

沒有內置的方式做到這一點,但這是django-users郵件列表上友好的用戶提供給我的解決方案。如果其他人試圖做同樣的事情,我會在這裏重新發布他的建議。

  1. 要確定當前視圖的特性在你的中間件,並相應地進行處理,和;:

    這是否有用

  2. 由於各種原因,你不想使用混合或裝飾來實現類似的結果。

這將檢查傳遞給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 
0

如果它取決於視圖,它應該可能是該視圖的混合。如果你正在做的事情就像一個菜單依賴於積極的看法,我會做目前的URL名稱的反向查找:

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

+0

在某些情況下,這些絕對是潛在的解決方法。但是Mixins必須在每個視圖的繼承層次結構中聲明,如果你基本上在任何地方都需要mixin,這可能會成爲一個問題。這不是中間件更好地處理的情況嗎?如果路徑可通過'request.path_info'獲得,爲什麼不在'request.view'使視圖實例本身可用?更令人驚訝的是:視圖實例在_template context_中可用:我可以簡單地用'{{view.my_attribute}}'來獲取view屬性......但是爲了處理它,我需要使用模板標籤。奇。 – tino

+0

對不起,我們可以直接使用視圖實例,它不是基於類的視圖的一個很好的擴展嗎?它可以讓你在全局範圍內做一些事情,你現在只能在個案基礎上用mixin來完成。或者使用裝飾器,這對初學者來說是一個相當難以訪問的功能。在任何情況下,在模板中公開視圖實例似乎有點愚蠢,但不通過請求對象。而且,我也可能在這裏錯過了一些完全基礎的東西。 :) – tino

1

另一種解決辦法是創建一個新的視圖類:

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