Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect from Generic View DetailView in Django

I'm using Django's class based DetailView generic view to look up an object for display. Under certain circumstances, rather than displaying the object, I wish to back out and issue a HTTP rediect instead. I can't see how I go about doing this. It's for when a user hits an object in my app, but without using the canonical URL. So, for example, on StackOverflow URLs take the form:

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

eg:

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

You can actually type anything as the seo_friendly_slug part and it will redirect you to the correct canonical URL for the object looked up via the PK.

I wish to do the same in my DetailView. Retrieve the object, check that it's the canonical URL, and if not redirect to the item's get_absolute_url URL.

I can't return an HttpResponseRedirect in get_object, as it's expecting the looked up object. I can't seem to return it from get_context_data, as it's just expecting context data.

Maybe I just need to write a manual view, but I wondered if anyone knew if it was possible?

Thanks!

Ludo.

like image 385
Ludo Avatar asked Jun 23 '11 15:06

Ludo


1 Answers

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.

like image 82
Rolo Avatar answered Oct 28 '22 23:10

Rolo