Understanding Django Class Based Views – part 2: the TemplateView class

Written by Johannes on September 22, 2012 Categories: Django

Your ads will be inserted here by

Easy AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

You can find the first part of this series here.

Welcome to our second installment of the series. As we are not satisfied with our view merely stroking our ego we want to go a step further. After reading this post we want to be able to have our view stroke our ego with a nicely formatted (standards compliant) HTML-page, and possibly add some context to the whole thing. For this purpose we will progress a little further into django/views/generic/base.py and see what other classes we can find there.

Django provides us with three more classes we will take a look at right now (there’s a fourth one, a RedirectView, which we will pay no attention to for now):

  • ContextMixin(object)
  • TemplateResponseMixin(object)
  • TemplateView(TemplateResponseMixin, ContextMixin, View)

Now, the nomenclature of these classes already suggests that there are different kinds of classes used in Django’s class based views. We have View classes, and Mixin classes. So let’s take a view at what methods these classes provide, to understand their purpose.

We start out with the very simple class ContextMixin:

class ContextMixin(object):
    """
    A default context mixin that passes the keyword arguments received by
    get_context_data as the template context.
    """
 
    def get_context_data(self, **kwargs):
        if 'view' not in kwargs:
            kwargs['view'] = self # add view instance to context
        return kwargs

This little class does nothing more than provide a method that takes a number of keyword arguments and adds the class instance to the values (under the key 'view') before returning the keywords again. We will take a look at how nicely this plays into the framework of View classes, later. First we want to check out the second Mixin class TemplateResponseMixin. This class is a little bit more elaborate and provides some more magic that needs understanding:

class TemplateResponseMixin(object):
    template_name = None
    response_class = TemplateResponse # inherits from HttpResponse
 
    def render_to_response(self, context, **response_kwargs):
        return self.response_class(
            request = self.request,
            template = self.get_template_names(),
            context = context,
            **response_kwargs
        )
 
    def get_template_names(self):
        if self.template_name is None:
            raise ImproperlyConfigured # this will scold us if we
                                       # forget to name a template
        else:
            return [self.template_name]

One thing that should be noted is the use of the TemplateResponse class as return value of render_to_response. I will not go into the details of this class, but note that it inherits from the HttpResponse class with which we already made brief acquaintance in the last part of this tutorial.

We observe, that the Mixin classes provide us with additional functionality on top of the basic handling of requests provided by the View class. The ContextMixin is responsible for preparing the context dictionary, whereas the TemplateResponseMixin provides us with an interface to template rendering as well as returning the appropriate HttpResponse object.

So let’s take a look at the TemplateViewClass and see how it works:

Your ads will be inserted here by

Easy AdSense.

Please go to the plugin admin page to
Paste your ad code OR
Suppress this ad slot.

class TemplateView(TemplateResponseMixin, ContextMixin, View):
    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs) # prepare context data
        return self.render_to_response(context)   # return rendered http
                                                  # response object.

As TemplateView inherits from TemplateResponseMixin, ContextMixin and View we know how the view is dispatched: on a get request to an url pointing to TemplateView.as_view() TemplateView().get() is called. Any keywords arguments passed to the method (e.g., in urls.py) are passed into the context and sent to the initiate a TemplateResponse object in the TemplateResponseMixin. Therefore TemplateView().get() returns the according TemplateResponse.

With this knowledge, let’s put the TemplateView class to some use. Again, we start by inheriting our own personal view class from TemplateView (we could also call TemplateView.as_view() directly from urls.py with some configuration parameters):

# myapp/views.py
class MyTemplateView(TemplateView):
    pass
 
# myproject/urls.py
from django.conf.urls import patterns, include, url
from myapp.views importMyTemplateView
 
urlpatterns = patterns('',
    url(r'^mytemplateview/', MyTemplateView.as_view(), name='mytemplateview'),
)

Firing up our browser to point at http://myserver/mytemplateview results in a very disappointing Exception “ImproperlyConfigured at /mytemplateview/”. But we should have anticipated that if we read the code closely. Obviously, a class named TemplateView should require a template to work. So we’ll do our view the favor and provide a little template and register it with our class:

<html>
    <head>
        <title>My Template View</title>
    </head>
    <body>
        <h1>My Template View</h1>
        <p>Hello Handsome!</p>
    </body>
</html>
# myapp/views.py
class MyTemplateView(TemplateView):
    template_name = "mytemplateview.html"

If we point our browser to /mytemplateview/ again we will be greeted by the familiar uplifting welcome, complimenting our looks. So now, let’s go and add some context to that. For this we simply override the get method of TemplateView (don’t forget to explicitly call the parents get method, though):

# myapp/views.py
class MyTemplateView(TemplateView):
    template_name = "mytemplateview.html"
 
    def get(self, request, *args, **kwargs):
        kwargs['greeting'] = 'Bonjour' # add a keyword
                                       # and value to the context
        return super(MyTemplateView, self).get(request,  # call get
                                               *args,    # method of
                                               **kwargs) # TemplateView
                                                         # class

We can now access that context in the template just as we’re used to:

<html>
    <head>
        <title>My Template View</title>
    </head>
    <body>
        <h1>My Template View</h1>
        <p>{{ greeting }} Handsome!</p>
    </body>
</html>
No Comments

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre user="" computer="" escaped="">