[Fixed]-Redirect from Generic View DetailView in Django

16👍

This isn’t a natural fit for DetailView. To do this you need to override the get method of BaseDetailView, which looks like:

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)

So in your class you’d need to provide a new get method which did the URL check between fetching the object and setting up the context. Something like:

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)

As you end up overriding so much of the functionality it becomes questionable whether it’s worth actually using a generic view for this, but youknow.

👤Rolo

10👍

Developing on Rolo’s answer and comments, I came up with the following generic view to serve this purpose:

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

This is used in the same manner as the normal DetailView, and should work for any model which implements get_absolute_url correctly.

Leave a comment