Переадресация из общего представления ViewView в Django - PullRequest
16 голосов
/ 23 июня 2011

Я использую общий вид DetailView на основе классов Django для поиска объекта для отображения.При определенных обстоятельствах, вместо того, чтобы отображать объект, я хочу отступить и вместо этого выдать HTTP rediect.Я не вижу, как я делаю это.Это когда пользователь нажимает на объект в моем приложении, но без использования канонического URL.Так, например, в StackOverflow URL-адреса имеют вид:

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, и она перенаправит вас на правильный каноническийURL для объекта, который ищется через PK.

Я хочу сделать то же самое в моем DetailView.Извлеките объект, проверьте, что это канонический URL-адрес, и если нет, перенаправьте на URL-адрес get_absolute_url элемента.

Я не могу вернуть HttpResponseRedirect в get_object, так как он ожидает поиска объекта.Кажется, я не могу вернуть его из get_context_data, поскольку он просто ожидает контекстные данные.

Может быть, мне просто нужно написать ручное представление, но я подумал, знает ли кто-нибудь, возможно ли это?

Спасибо!

Людо.

Ответы [ 2 ]

15 голосов
/ 23 июня 2011

Это не совсем подходит для DetailView. Для этого вам нужно переопределить метод get BaseDetailView, который выглядит следующим образом:

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)

Так что в вашем классе вам нужно будет предоставить новый метод get, который проверяет URL-адрес между извлечением объекта и настройкой контекста. Что-то вроде:

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)

Поскольку в конечном итоге вы переопределяете большую часть функциональности, становится сомнительным, стоит ли на самом деле использовать универсальное представление для этого, но вы знаете.

10 голосов
/ 12 октября 2012

Развивая ответ и комментарии Роло, я пришел к следующему универсальному представлению для этой цели:

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.

...