Getting RequestContext in Your Templates

Lately, we’ve been taking over projects from people who began building their first site in Django, but either got in over their head or just found they didn’t have the time to continue. As I review the existing code, the first issue I typically see is using the render_to_response shortcut without including the RequestContext, preventing context processors from being used in the templates. The standard symptom is when people can’t access MEDIA_URL in their templates.

Here are a few ways to add RequestContext to your templates.

Option #1: Adding RequestContext to render_to_response

The Django documentation recommends passing RequestContext as an argument to render_to_response like this:

from django.shortcuts import render_to_response
from django.template import RequestContext

def my_view(request):
    # View code here...
    return render_to_response('my_template.html',
                              my_data_dictionary,
                              context_instance=RequestContext(request))

This works, but as you can see, it adds a fair amount of repetitive code to your views.

Option #2: Wrapper for render_to_response

Don’t repeat yourself. Create a wrapper like this, courtesy of Django Snippet #3

from django.shortcuts import render_to_response
from django.template import RequestContext

def render_response(req, *args, **kwargs):
    kwargs['context_instance'] = RequestContext(req)
    return render_to_response(*args, **kwargs)

Option #3: Use Generic Views

Django’s generic views include RequestContext by default. Although the docs show them being used in urls.py, you can just as easily use them in your views. James Bennet gave some examples of this technique on his blog back in ‘06. It looks something like this:

from django.views.generic import list_detail

def my_view(request):
    # View code here...
    return list_detail.object_list_(request,
                                    queryset=Foo.objects.all(),
                                    extra_context=some_dict)

Most views can be distilled down to either a single object or list of objects with some extra variables thrown in. When they can’t, simply use direct_to_template.

Option #4: Getting Creative with Decorators

I came across a technique I hadn’t seen before a couple of days ago when poking around django-cashflow. It monkey patches render_to_response using option #1 above, then creates uses a decorator for it. The code looks like this:

def render_to(template_name):
    def renderer(func):
        def wrapper(request, *args, **kw):
            output = func(request, *args, **kw)
            if not isinstance(output, dict):
                return output
            return render_to_response(request, template_name, output)
        return wrapper
    return renderer

@render_to('my_template.html')
def my_view(request):
    # View code here...
    return some_dict

Pretty slick.

How About You?

I use generic views for a few of reasons.

  • It is less verbose than option #1
  • Options 2 & 4 are clever, but I prefer to use built-ins whenever possible. One of the reasons I chose Python over Ruby is because it isn’t a TIMTOWTDI language. Wrappers and shortcuts are great, but they can also make it more difficult for someone else to jump into your code and start working. With generic views, you get sane defaults and everything is already fully documented and clear to other Django developers.
  • They provide a standardized naming scheme for your templates. Again allowing other developers to jump right into your code without having to learn your style.

So how about you? What technique do you use and why?

Comments

  • May 10, 2008 at 3:44 p.m. #
    David, biologeek chimed in with:

    What about django.views.generic.simple.direct_to_template?

  • May 10, 2008 at 3:44 p.m. #
    Matt Wilson responded:

    I’ve always used

    render_to_response(‘template’, RequestContext(request, data_dict))

    which seems to work fine, and isn’t so bad.

  • May 11, 2008 at 4:01 p.m. #
    SmileyChris mentioned:

    Like David suggested, just use the direct_to_template view as you would the render_to_response template (but passing request as the first argument).

    Easy peasy.

  • May 11, 2008 at 8:33 p.m. #
    Peter Baumgartner piped up:

    David, I mentioned direct_to_template in Option 3 (my personal choice), but only use it when one of the other generic views doesn’t make more sense.

  • May 12, 2008 at 1:43 a.m. #
    LMZ responded:

    +1 for direct_to_template! simple + beautiful and without inventing the wheel.

  • May 12, 2008 at 8:40 a.m. #
    njharman commented:

    I do this. I do repeat the “context = RequestContext(request)” line in (most)every view but I like being explicit like that.

    context = RequestContext(request)
    context[“somevar”] = “foo”
    context[“othervar”] = “bar”
    return render_to_response(“template.html”, context)

  • May 12, 2008 at 10:40 a.m. #
    Empty added:

    Nice writeup. Another good resource to point people to.

  • May 13, 2008 at 8:50 a.m. #
    sean commented:

    thanks for your code!
    it helps me a lot in using RequestContext

  • May 15, 2008 at 12:28 a.m. #
    David, biologeek chimed in with:

    In fact, direct_to_template is more a replacement for #1 given the fact it does exactly the same as #2, otherwise, if a generic_view already exists (#3), it’s more interesting to use it like you mention.

  • May 15, 2008 at 8:12 a.m. #
    Peter Baumgartner mentioned:

    David, direct_to_template is a generic view.
    django.views.generic.simple.direct_to_template :)

  • March 19, 2009 at 3:19 a.m. #
    iongion responded:

    i like the decorator thingy, looks so pretty, can u provide a better example with the view, no matter what i return i always get “object has no attribute ‘status_code’”

    i am no django expert, but this make me think the view function must respond with a HttpResponse, which in turn needs a rendered template, then what is the purpose of render_to (I COULD SERIOUSLY BE MAKING MISTAKES)

  • July 14, 2009 at 8:36 a.m. #
    Nate added:

    Thanks a bunch – as an aspiring djangoer, this is great stuff! I still prefer method 2, but probably because I don’t utilize generic views well enough yet.

    Awesome Post.

  • July 26, 2009 at 2:43 p.m. #
    Stefan chimed in with:

    Excellent post, thank you!

  • March 28, 2010 at 3:24 p.m. #
    mikemike responded:

    How about just using a custom context processor?

  • April 12, 2010 at 6:17 p.m. #
    iJames commented:

    Option 3 sure does seem interesting and compact and I’m trying it right now! :-)

    So this means that for each list or object, there must be a template that is named appropriately based upon that object yes?

    Also, what I’m not understanding is how most views can be distilled down to a list of objects or a single object. I’m thinking about a standard website with a logged in user, a list of perhaps random ads, a list of context based options, a set of context based menus, and then the main content which could have a list or two or three in it. So is the idea that everything gets put into RequestContext? Which sounds good to me.

    But what if I can’t distill it down all the way? Do I still pick one object or list to be the main one and stick with generic views by slamming the other ones into the extra dict? Or is there a fallback like render_to_response? I guess by picking the right object, it allows me to choose the right template. But then am I only allowed one template for each object_list and object_info?

    Great breakdown of information!

    Thanks!!!

    James

  • May 13, 2010 at 3:39 a.m. #
    Lorenzo mentioned:

    Right now i’m in love with http://bitbucket.org/offline/django-annoying/ ‘s decorators:

    @render_to()
    @ajax_request()

Got something to say?





Our Products

Gondola
Gondola is a hosted CMS that gives designers a powerful and easy platform to create amazing geo-enabled Websites.
Trailmapping
Still in development, Trailmapping is a GPS enabled trail guide and trip logger.

Categories

Archives

Elsewhere

What we’ve been up to online

Interested in working with us?
Fill out the form below or contact us at:

PO Box 774441
Steamboat Springs, CO
80477

ph: 970.879.8810
fx:  970.367.8596
info@lincolnloop.com