The Django class war

When I wrote the first view for my application it was written as a function. If you follow the Django tutorial, it recommends switching to generic views using classes.

It turns out this isn’t necessarily a straightforward decision. Opinion on the value of view classes seems to be divided.

To give it some context, here’s the function based view:

from django.shortcuts import render
from .models import AccountType

def account_type_list(request):
  list = AccountType.objects.order_by('name')
  context = {'account_type_list': list}
  
  return render(request, 'finance/account_type_list.html', context)

And here’s the version using a class based on the generic list view:

from django.views import generic
from .models import AccountType

class AccountTypeList(generic.ListView):
  model = AccountType

They do exactly the same thing but there’s less code to write to use the class based view.

That said, the class view required a couple of changes to the template. First of all, it defaults to a template name based on the model name. For the list view of the account type model that will be accounttype_list.html – slightly different to the name I used in the function view, but not a major change.

The other difference is that the data is sent in a default variable called object_list, so in my template I need to change:

{% if account_type_list %}
<ul>
    {% for account_type in account_type_list %}

To read:

{% if object_list %}
<ul>
{% for account_type in object_list %}

Alternatively, I could change the class code to use the original template name and pass the original variable name:

class AccountTypeList(generic.ListView):
  model = AccountType
  context_object_name = 'account_type_list'
  template_name = 'finance/account_type_list.html'

There are pros and cons to making the context object name and template name explicit in the code. What you lose in brevity you gain in clarity.

Finally, the class based version doesn’t make the sort order explicit. I could achieve that by replacing:

  model = AccountType 

With:

  queryset = AccountType.objects.order_by("name")

It’s also possible to set the default order for an object in its model definition, but again, that’s at the expense of clarity in the actual view code.

By clarity, I mean the ability to glance at the code and know what it’s doing. I find the function view much clearer in that respect. To fully understand the class views you need to know the Django object model. That becomes even more important when moving beyond really simple use cases where the default object behaviours aren’t sufficient.

Object oriented programming is a powerful paradigm, but I think it works best when you’re designing your own object models. It’s when you start using existing models and creating objects that inherit from complex hierarchies of parent classes that things start to go wrong.

The strength of object inheritance is that a lot of the work can be done in the parent objects, leaving you to fill in the specifics in your child objects. That comes at the cost of that work being hidden, and it’s important, as a programmer, that you understand exactly what those parent objects are doing for you.

The Django View object model uses a combination of parent inheritance and multiple inheritance via mixins. The Classy Class-Based Views site is an essential reference for users of Django’s view model, and this is what it shows for the generic list view:

No fewer than six objects contribute to the attributes and methods of the generic list view. No wonder that reference site is considered essential reading.

The Python language comes with guidance in the form of “The Zen of Python” which breaks the guiding principles of the language into a number of aphorisms.

Amongst these are:

Explicit is better than implicit
Simple is better than complex
Flat is better than nested
If the implementation is hard to explain, it’s a bad idea

At first glance it seems to me that the Django View model fails on those counts. So is it worth using?

My gut feel is that it depends on your use case for Django. If you’re a full time Django developer, working on a major system, it’s probably worth persevering with the object model.

For more complex views, you’ll probably end up using the base View class and creating your own classes that inherit from that – you’ll end up with clearer code than you would by attempting to use a generic view. The generic views have their place for run of the mill CRUD operations on simple models, but run out of steam when the requirements get more complex.

As an occasional developer, I want code I can come back to and understand quickly in a year’s time, with little use of Django in the interim. I think the functions fit that requirement better and make more sense for me.

in Finance Project

Related Posts