There’s a super nice super elegant productivity trick for Django class based views. Something that is not very well know, as I discovered at last week’s djangocon. So… time to share it!
The problem? Getting information into your template’s context. What most
people do is to overwrite get_context_data(), just like the example from
the django 1.5 docs
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherDetailView, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
In the template you’d use it like this:
{% for book in book_list %}
...
{% endfor %}
The solution? A new feature in Django 1.5
: Django’s generic class based views now automatically include a view
variable in the context. This variable points at your view object. So… you
basically never need to modify get_context_data() anymore! Example:
from django.views.generic import TemplateView
class SomethingView(TemplateView):
template_name = "something.html"
title = "My beautiful list of books"
def books(self):
return Book.objects.all()
# Note: no get_context_data() here!
The template then uses the automatic view variable to grab the list of
books and the title:
<h1>{{ view.title }}</h1>
<ul>
{% for book in view.books %}
<li>{{ book }}</li>
{% enfor %}
<ul>
Isn’t that wonderful? It fits Django’s philosophy perfectly: the templates
should be dumb, the processing should happen inside the view. Now it is dead
easy to “just add a method” to calculate something, the method will
automatically be available in the template as
view.your_quick_helper_method.
No more tedious duplication like this:
from django.views.generic import TemplateView
class SomethingView(TemplateView):
def books(self):
return Book.objects.all()
def get_context_data(self, **kwargs):
context = super(SomethingView, self).get_context_data(**kwargs)
context['books'] = self.books()
# ^^^ bad duplication.
return context
I mean, context['books'] = self.books(), that’s just plain unnecessary
duplication. But… no need to do it anymore! Just call the method or grab the
attribute directly.
Some notes:
It works for Django’s generic class based views. So if you subclass
TemplateView or EditView or so, you’re fine.
Behind the scenes, it is the ContextMixin
that provides the basic get_context_data() method that injects the
view variable into the context.
Django’s normal view restrictions apply. Attributes are fine. Methods with
just self as a parameter are fine.
Methods that need an extra parameter (def books(self, category)) won’t
work, as django’s template language doesn’t allow you to call methods like
that.
Similarly, attributes and methods prefixed with an underscore (“private”) aren’t available.
Hm, I think this is an essential (and very handy! part of Django’s view mechanism. I added the original ticket. But… I notice now that it is hardly mentioned in the docs.
Should this need to be better documented? I’m thinking about changing the adding extra context paragraph to “just stick a method/attribute on the view” instead of “mess with get_context_data()”. Is this a good idea?
My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.
Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):