2011-06-23 13 views
16

Używam widoku generycznego DetailView klasy Django do wyszukiwania obiektu do wyświetlenia. W pewnych okolicznościach zamiast wyświetlać obiekt, chcę wycofać się i zamiast tego wydać polecenie redestowania HTTP. Nie widzę, jak to robię. Dzieje się tak, gdy użytkownik uderza w obiekt w mojej aplikacji, ale bez użycia kanonicznego adresu URL. Tak więc, na przykład, na URL StackOverflow przybrać formę:Przekierowanie z widoku ogólnego View DetailView w Django

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

np

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

Rzeczywiście można wpisać cokolwiek jako część seo_friendly_slug i będzie przekierowanie do właściwej kanonicznym URL dla obiektu spojrzał w górę przez PK.

Chciałbym zrobić to samo w moim DetailView. Odzyskaj obiekt, sprawdź, czy jest to kanoniczny adres URL, a jeśli nie, przekieruj go na adres URL get_absolute_url elementu.

Nie mogę zwrócić HttpResponseRedirect w get_object, ponieważ oczekuje obiektu wyszukującego. Nie mogę go zwrócić z get_context_data, ponieważ oczekuje tylko danych kontekstowych.

Może po prostu muszę napisać widok ręczny, ale zastanawiałem się, czy ktoś wie, czy to było możliwe?

Dzięki!

Ludo.

Odpowiedz

15

To nie jest naturalne dopasowanie do DetailView. Aby to zrobić, trzeba zastąpić metody GET z BaseDetailView, który wygląda tak:

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) 

Więc w swojej klasie ty że trzeba zapewnić nowe metody GET który dokonał sprawdzenia URL między pobierania obiekt i konfigurowania kontekst. Coś jak:

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) 

Jak skończyć nadrzędnymi tyle funkcjonalności staje się wątpliwe, czy warto faktycznie stosując ogólny pogląd na to, ale youknow.

+1

Możesz po prostu zadzwonić do metody pobierania rodziców w innym przypadku. Byłoby znacznie czystsze. Jest to całkowicie opłacalne, ponieważ ogólne widoki oparte na klasach są rozszerzone o niestandardową funkcjonalność. – vimukthi

+1

To, co jest dobre w twoim podejściu, to to, że nie musimy się martwić, jeśli implementacja BaseDetailView.get zmieni się, ale wadą jest to, że musimy dwukrotnie pobrać obiekt dla każdego żądania, co dla mnie nie jest warte potencjalnego uderzenia wydajności/skalowalności. – Rolo

+0

Aby uniknąć podwójnego trafienia w 'get_object', możesz go przesłonić we własnej klasie lub mixin i przedmowie, zaznaczając' if hasattr (self, 'object', None) '; jeśli sprawdzenie się powiedzie, zwróć 'self.object' inaczej nazwij polecenie' get_object'. Dokładnie tak, jak zaimplementowano @Raumkraut (https://stackoverflow.com/a/12858110). – interDist

10

Opracowanie na odpowiedź i komentarze Rolo, w wymyśliłem następujący widok generyczny służyć temu celowi:

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); 

ten jest wykorzystywany w ten sam sposób, jak w normalnym DetailView i powinien działać na każdym modelu, który implementuje poprawnie poprawkę get_absolute_url.

Powiązane problemy