2011-06-23 31 views
16

我使用Django的基於類的DetailView通用視圖來查找顯示對象。在某些情況下,我不想顯示對象,而是希望退出併發出HTTP rediect。我看不到我是如何去做這件事的。這是爲了當用戶在我的應用程序中擊中對象時,但不使用規範URL。因此,例如,在計算器上的URL的形式是:從通用視圖重定向在Django DetailView

http://stackoverflow.com/<content_type>/<pk>/<seo_friendly_slug> 

如:

http://stackoverflow.com/questions/5661806/django-debug-toolbar-with-django-cms-and-django-1-3 

實際上,你可以鍵入任何作爲seo_friendly_slug的一部分,它會將您重定向到正確規範的網址爲對象通過PK擡頭看。

我希望在我的DetailView中做同樣的事情。檢索該對象,檢查它是規範URL,並且如果不重定向到該項目的get_absolute_url URL。

我無法在get_object中返回HttpResponseRedirect,因爲它期望查找對象。我似乎無法從get_context_data中返回它,因爲它只是期待上下文數據。

也許我只需要寫一個手動視圖,但我想知道是否有人知道它是否可能?

謝謝!

魯多。

回答

15

這不適合DetailView。要做到這一點,你需要重寫BaseDetailView的get方法,它看起來像:

class BaseDetailView(SingleObjectMixin, View): 
    def get(self, request, **kwargs): 
     self.object = self.get_object() 
     context = self.get_context_data(object=self.object) 
     return self.render_to_response(context) 

所以在你的類,你就需要提供沒有獲取對象和設置的URL檢查了新的get方法上下文。喜歡的東西:

def get(self, request, **kwargs): 
    self.object = self.get_object() 
    if self.request.path != self.object.get_absolute_url(): 
     return HttpResponseRedirect(self.object.get_absolute_url()) 
    else: 
     context = self.get_context_data(object=self.object) 
     return self.render_to_response(context) 

當你結束了覆蓋如此多的成爲懷疑它是否真正使用通用的視圖這一點,但你知道的更多的價值功能。

+1

您可以在此處調用父項get方法。它會更乾淨。這是完全值得的,因爲基於類的通用視圖可以擴展爲自定義功能。 – vimukthi

+1

你的方法的好處在於,我們不需要擔心BaseDetailView.get的實現是否會發生變化,但缺點是我們需要爲每個請求執行兩次對象檢索,對我而言,這不是值得潛在的性能/可擴展性打擊。 – Rolo

+0

爲了避免雙重命中'get_object',你可以在你自己的類中重寫它,或者用一個檢查來混合它,如果hasattr(self,'object',None)';如果檢查成功,則返回'self.object',否則調用父級的'get_object'。完全如@Raumkraut實現(https://stackoverflow.com/a/12858110)。 – interDist

10

上羅洛的回答和評論發展,我想出了下面的通用視圖來達到這個目的:

from django import http 
from django.views import generic 


class CanonicalDetailView(generic.DetailView): 
    """ 
     A DetailView which redirects to the absolute_url, if necessary. 
    """ 
    def get_object(self, *args, **kwargs): 
     # Return any previously-cached object 
     if getattr(self, 'object', None): 
      return self.object 
     return super(CanonicalDetailView, self).get_object(*args, **kwargs) 

    def get(self, *args, **kwargs): 
     # Make sure to use the canonical URL 
     self.object = self.get_object() 
     obj_url = self.object.get_absolute_url() 
     if self.request.path != obj_url: 
      return http.HttpResponsePermanentRedirect(obj_url) 
     return super(CanonicalDetailView, self).get(*args, **kwargs); 

這是在相同的方式與正常的DetailView使用,並且應爲任何模型工作當中正確實施get_absolute_url