Перенаправление из 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, так как он просто ожидает контекстных данных.
Возможно, мне просто нужно написать ручное представление, но я подумал, знает ли кто-нибудь, возможно ли это?
Спасибо!
Людо.
Ответы
Ответ 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
.