Tuesday, May 31, 2011

Django Class-based Views

Since the release of Django 1.3, developers can choose to use class-based views in their web apps. Since the announcement of class-based views, there has been said a lot about them. As with all changes, there are pros and cons, people who are excited and people who are disappointed. I, and I guess a lot of people with me, are excited by the class-based views, but disappointed by the documentation Django gives with them. Time to try to clear things up.

What do I like about Django's class-based views?

Well, to start with: consistency. It might sound a bit lame, but I think it's a great thing that, following models and forms, views are now also part of the class-based club. I somehow always thought it was weird to write your forms and models in a class, but your views in a function. This weird feeling is now gone. Lucky me.

Secondly: consistency. Again? Yes, again, because you can now force your own code to be more consistent, by using subclassing. You can, for example, write your own superclass view template and let all your other views subclass it.

And last: Subclassing. I found it hard to find an example to make my point, but it might be obvious that subclassing is a good thing in general. If you have two slightly different views, subclassing reduces the amount of code that you will copy/paste and adapt a little, and thus reduces redundancy. Positivity all over the place!

What I don't like about Django's class-based views?

I have mentioned it before in this post: The documentation. Whenever you Google or Bing or whatever for Django class-based views, you will encounter a bunch of pages about Django's class-based generic views. It may be something personal, but I don't really like generic views. Whenever I use them, it feels like I am losing control over the website I am trying to create.

Moreover, the Django documentation seems to put a lot of custom logic, like what templates to use, in the URL config. Which is another thing that rings my developer alarms. The URL config, in my opinion, is a bunch of rules that tells my application what view should be called on what URL. Taking away some of the functionality of the views and putting it into the URL config just doesn't feel right.

So we don't want the class-based generic views, but ordinary class-based views. The way we used to have views in Django 1.2.x, but now with classes. So we Google and Bing and whatever along, to find any documentation covering ordinary class-based views. My Google skills are not something to brag about, but I could not find any information about non-generic class-based views.

So what do we do now?

I talked this over with one of my colleagues. He agreed with me about the lack of non-generic class-based views documentation and the fact that Django putting logic into the URL config is kind of ugly. He told me how he uses the class-based views in his projects and I decided to go with it, just because it made some sense to me.

In my current projects, all of my views are subclassing django.views.generic.View and optionally django.views.generic.base.TemplateResponseMixin. That way you can easily convert your former function-based views to new and cool class-based views. A code example to summarize and conclude.

class SomeFormView(TemplateResponseMixin, View):
    template_name = 'some_form.html'

    def get(self, request):
        form = SomeForm()

        return self.render_to_response({
            'form': form,
        })

    def post(self, request):
        form = SomeForm(request.POST)

        if form.is_valid():
            form.save()
            messages.success(request, 'Your form has been saved!')

        return self.render_to_response({
            'form': form,
        })


class AjaxThingView(View): 
    # Note that I don't subclass the TemplateResponseMixin here!

    def get(self, request):
        return HttpResponse(status=404)

    def post(self, request):
        id = request.POST.get('id')

        # Do something with the id
        return HttpResponse('some data')