Embracing class-based views

I recently realized that class-based views are a beautiful, powerful tool to build clean, streamlined views that are easy to understand and maintain.

Let me make my case with a trivial example. Let’s have a look at the canonical way to deal with a form in function-based views:

def contact(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ContactForm(request.POST) # A form bound to the POST data
        if form.is_valid(): # All validation rules pass
            # Process the data in form.cleaned_data
            # ...
            return HttpResponseRedirect('/thanks/') # Redirect after POST
            form = ContactForm() # An unbound form
        return render_to_response('contact.html', {'form': form,})

What we have here is a good deal of boilerplate code, complete with an ugly nested if to deal with the submit and validation logic. Hardly the kind of style I would promote.

With class-based views, we can instead write:

class Contact(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
    success_url = '/thanks/'
    def form_valid(self, form):
        # Process the data in form.cleaned_data
        return super(Contact, self).form_valid(form)

The boilerplate code has been abstracted away, we can express the easy cases in a declarative style and we can concern ourselves with just the application logic. Of course, there are more advantages than this simple example can show: pre-made views, a good deal of pre-made composable mixins and, of course, the full power of OOP.

Yet, discovering and adopting the new style is more difficult than it should be. The documentation is filled with function-based view examples that should really be ported to class-based views, and even the section on class-based view is a dump of lists with little to none information on how the details come together.

So, expect to have to dive into the source code, ask around and look for sample code (I plan to post some here in my blog as I discover things). And, if you’re a long-time Django user, or if you’re just approaching Django and you rely a lot on Google and code samples, expect to find a mismatch between old best practices and class-based views.

For example, class-based views provide an obvious means to compose view functionality: multiple inheritance and mixins. And function-based views did provide an obvious means to compose view functionality: function decorators. While class-based views do support old function decorators, when I’m using the two extensively, I’m constantly aware that I am mixing two paradigms, I’m constantly looking out for potential trouble at the intersection of the two worlds, and I’m aware that I need to make a conscious choice between the two.

Should these difficulties stop you from adopting class-based views in your current project? It depends on your context. Should these difficulties stop you from looking into adopting class-based views for your current or your next project? Not really.

In real life, tawmas goes by the name of Tommaso R. Donnarumma. When asked, he describes himself as an Italian in Québec; a passionate programmer who has also been a project manager and a sysadmin; an Ubuntu user; an avid photographer; a lover of books, Baroque music, jazz, red wines, white beers; a gamer; an incurable curious.

Leave a Reply

Your email address will not be published. Required fields are marked *