Подтвердить что ты не робот

Перенаправление из Generic View DetailView в Django

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

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

например:

http://stackoverflow.com/info/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, так как он просто ожидает контекстных данных.

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

Спасибо!

Людо.

4b9b3361

Ответ 1

Это не подходит для 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)

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

Ответ 2

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

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.