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):