Jeff Croft

I’m a product designer in Seattle, WA. I recently worked at Simply Measured, and previously co-founded Lendle.

Some of my past clients include Facebook, Microsoft, Yahoo, and the University of Washington.

I’ve authored two books on web and interactive design and spoken at dozens of conferences around the world.

I’m currently accepting contract work and considering full-time opportunities.

Blog entry // 02.25.2006 // 11:30 AM // 29 Comments

Django Templates: The Power of Inheritance

For this, the second entry in my series of posts about the Django template language (part one was an introduction), I’ve chosen to focus on its inheritance capability, which is probably its most powerful feature. Inheritance makes it possible to whip up new pages for your site very quickly and easily.

Because many of the readers of this site are bloggers themselves, I’m going to use an example of a simple blog template in an attempt to demonstrate how inheritance works in Django’s template language.

First, a quick syntax lesson: Django uses double curly braces to notate variables. For example, to access a blog entry object, you might use {{ entry }}. Dots are used to access attributes of variables. Our {{ entry }} variable may have attributes such as {{ entry.title }} and {{ }}, for example. Django templates also have tags, which use the curly-brace + percent sign notation. Examples of tags are if statements and for loops. A for loop in Django’s template language looks like this: {% for entry in blog %}...{% endfor %}.

With that out of the way, let’s start by throwing together some basic HTML for a blog with a header and two columns — one for content and one to act as a sidebar.

That should look pretty familiar to most of you. Let’s save this file as base.html. This would be a good time to point out that Django templates always use the .html extension, even though they can be used to produce any text format. The use of .html was chosen simply to active syntax color coding for HTML in text editors, since Django templates are most-commonly used with HTML.

What we’re striving for with base.html is a skeleton page structure defining elements that will be on every page in the site. We now need to define regions, which Django calls “blocks,” to be filled in by child templates. We’ll use Django’s {% block %} tag to do this. Take a look:

Here, I’ve set aside four blocks: title, extrahead, content, and sidebar. Note that I’ve included the title “Generic Page” in the title block, but the other blocks are currently empty. Now, we can create child templates that “extend” our base template. When one template extends another, it inherits everything within the parent template, but has the capability to overwrite some or all blocks. Going with our blog example, let’s make a child template for our individual entries and call it entry.html.

The first line tells Django that this template “extends,” or is a child of, the base.html template we already created. Note the omission of the .html extension. Then, we’ve overwritten the title block with the contents of the {{ entry.title }} variable. Finally, we’ve filled in the content block with some simple HTML to display our blog entry. In this template, we didn’t do anything with the blocks sidebar or extrahead, so they would simply remain unchanged from the base.html template. The evaluated output of this template would look something like this:

Now, let’s say we have some entries in our blog that we want to treat in a special way. Perhaps entries about music have an additional stylesheet. All we need to do it create a new template (we’ll call it entry_music.html) and toss our stylesheet into that extrahead block we set aside earlier, like this:

The entry_music template extends entry, which in turn extends base, so the result is:

I just had an idea. What if, on music-related entries, we put one of those nifty “What I’m currently listening to” lists in the sidebar? That’d be slick, right?

Within any block, Django gives you access to a variable called {{ block.super }}, which grabs the contents of the current block from the parent template(s). Using {{ block.super }}, it’s incredibly simple to add our “what I’m listing to” bit. In entry_music:

This will fill the sidebar with the contents from the parent template (currently our blogroll), plus the new content we’ve added in the block (the “What I’m listening to” list).

By now, you should be getting the idea. From here, I might go about making a template for blog archives. We could call it archive.html — and have it extend base.html. Then, I might create archive_yearly.html, archive_monthy.html, and archive_daily.html — each of which would extend archive.html. Each of these templates would probably just contain a filled-in {% block content %} tag.

If I suddenly decide I need to add something to every page on the site — say, a search field — all I need to do it put it in base.html. All of the templates extend base.html (or one of it’s children), so they’ll all get the added search field. If I want to add something to every archive page — maybe some javascript for rolling archives — I could just add an {% extrahead %} tag to archive.html with a link to my javascript. archive_yearly.html, archive.monthly.html, and archive_daily.html would inherit the added javascript, since they all extend archive.html.

I should note, too, that you aren’t limited to one base template (nor does it have to be called base). Many of our World Online sites, for example, have a handful of first-level templates. Besides our main base template, we might have one called base_small for pop-up windows, or base_wide for when we want to remove the sidebar and have the content take up the full width.

I’m not sure how well all of this comes across in writing. I’m not even sure how well it comes across when it’s told to you. It was explained to me one morning by Wilson Miner, who is probably the foremost authority on Django templates and is a well-spoken and smart individual — but the power and simplicity of Django’s template inheritance still didn’t really sink in until I actually went and built something with it.

The ability to say, “For this new page, give me the same HTML I’m using for blog entries, but change this one little piece,” is an incredible timesaver. You’ve really got to give it a try.

Next up in the Django template series: built-in filters, which let you manipulate the output of variables in all sorts of cool ways.


  1. 001 // Justin Perkins // 02.25.2006 // 2:25 PM

    That came across very well, thanks for putting the time into it.

    I’m very intrigued with Django, I like the inheritance model that seems to be a core concept. It vaguely reminds me of forms in textpattern (although stronger and more abstract), which is probably the single greatest feature of txp.

    So where is the demo Django site where one could play around to see how it looks “out of the box”?

  2. 002 // Michael Hessling // 02.25.2006 // 2:36 PM

    Y’know, I first heard of Django when Simon introduced it, but your the first one to really show me how powerful it is. I’m off to read about Snakes and Rubies. Looking forward to more from you.

  3. 003 // Jeff Croft // 02.25.2006 // 3:22 PM


    Django itself doesn’t look like much “out of the box.” Remember, Django is an application framework, not an application itself. A Django application (like, say, a blog app or a photo gallery tool) may have default templates that look a certain way “out of the box,” but not Django itself. Django does include the automatic admin application, though, and that has a default “look and feel” to it (which is really great — Wilson designed it, and did a great job). I don’t know of a demo site where you could play with the admin (although that’s not a bad idea), but this tutorial offers quite a few screenshots:…


    Glad to hear it! A lot of the Django info that is out there is focused more on the programming/python side of things — and understandably so. But, one of the things I love about Django is that it’s definitely built with the designer in mind, too — and the reason I wanted to do this series was to show other designers and front-end people how Django can benefit them, as well as the programmer-types.

  4. 004 // Justin Perkins // 02.25.2006 // 3:26 PM

    Oh, boy. Way more powerful than I thought. Thanks Jeff!

  5. 005 // Wilson Miner // 02.25.2006 // 6:30 PM

    Well done, young grasshopper. The student becomes the teacher.

  6. 006 // Wilson Miner // 02.25.2006 // 6:35 PM

    Another thing I still can’t get over about inheritance in Django templates is how easy it is to go from mockup to live site.

    If you’ve got a set of default templates for all your content (say, your blog archives) and you’ve got one page coded out in HTML and CSS, all you have to do is paste your HTML into base.html, add a few block tags and bam you’ve got a site that works.

    No chopping up content into separate includes, or adding a bunch of context variables to all your templates. I’m amazed every time I start a new Django site how I can go from mocked up content to dynamic, templated content in literally just a few minutes.

  7. 007 // P.J. Onori // 02.25.2006 // 7:54 PM

    Wow, that’s impressive. Seriously, this would make life tremendously easier.

    Great article.

  8. 008 // Justin Perkins // 02.26.2006 // 1:22 AM

    Thanks again, I got django (dee-jane-go) running on dreamhost now :)

    happy happy fun

  9. 009 // Michael Hessling // 02.26.2006 // 6:01 AM

    Jeff, you’re (see, I do know how to contract) very fortunate to have some serious Django-fu on your development team. You’re also fortunate to have someone showing you the way, which, again, is why I’m appreciating this series.

    PS: Did you know that your home page is gone?

  10. 010 // Jeff Croft // 02.26.2006 // 10:15 AM

    Justin: Awesome! Be sure to come by the #django channel on if you have questions.

    Michael: Yeah, between having Jacob and Matt on full-time, and being in constant contact with Adrian (and still in touch with Simon, as well), we’re in pretty darn good shape. not to mention, we’ve also got Wilson — who, like I said, probably know his way around the template language more than anyone anywhere. So yeah, I’ve got a lot of help. The nice thing is all of those guys are very willing to help others, too — especially in the IRC channels.

    I think my home page is fine right now, but you may have caught me in the middle of doing some backups. I took pieces of the site down in order to back up all the files. :)

  11. 011 // Peter Van Garderen // 02.26.2006 // 12:47 PM

    Great write-up.

    Please be sure to add your blog feed to the Django community page:… so that the community is easily notified when you add more to this series.

    Looking forward to your filters write-up.

  12. 012 // jd // 03.02.2006 // 10 AM

    Nice writeup, thanks!
    One of the things I dislike about Django templates is the need to get all those curly braces and percent signs right. I see I’m not the only one with that problem ;-)
    BTW, I am having a hard time entering this comment. I am using Firefox 1.0.7 and there are a couple of problems. The text cursor is one line above where I’m typing (bizarre); and the window has to be full width to use the comment field (scrolling doesn’t work properly).

  13. 013 // Ryan // 03.09.2006 // 3:26 PM

    Thanks so much for starting this series. We’re looking to switch development frameworks for our sites, and we really, really like Django. Your posts will definitely help us sell the idea in-house. Can’t wait for the next installment.

  14. 014 // Luke // 05.08.2006 // 7:09 PM

    Great article, I too am so impressed with how small my templates are, and free of cruft, since everything is defined once and then inherited.

    Just a quick correction: “This would be a good time to point out that Django templates always use the .html extension, even though they can be used to produce any text format” … not true in the development version anymore, mainly to allow the templates to be used with any file type, and because of the Python mantra “explicit is better than implicit”.

  15. 015 // Jeff Croft // 05.08.2006 // 7:17 PM


    You’re absolutely right. A few things have changed with regards to templates in the latest version.

  16. 016 // Nate Straz // 08.09.2006 // 8:24 AM

    Ah, block.super! That is what I was looking for! I missed the one reference to it in templates.txt. That’s something that should be mentioned in the tutorials and shown in an example. Thank you for mentioning it in this post.

  17. 017 // Peter Renshaw // 01.07.2007 // 6:01 AM

    Hi Jeff, found a broken url link on this page. The link should point to the ‘Introduction’ of the Django Templates: The Power of Inheritance. Instead it points to the following url

    Got a few questions because I’m working with django right at the moment trying to build a composite view of data using a main table with several linked ManyToMany tables. I notice the key here to building a composite page made up of many different pieces of linked data is to build a html page combining individual templates each building a block of data from a single table.

    • is it possible to combine the data into one queryset then call that object inside a single template?

    I’ve tried doing this with the ManyToMany using the DB API, Related Objects, ManyToMany as outlined in… with patchy results. The only advantage I can think of doing it this way is using 1 or few templates to build a view.

    I’ll instead try the technique you’ve outlined building inherited templates with a skeleton of html (a much simplier way to understand) with good results. I was just curious is it possible to do this another way?

    ps: have you thought of adding the filter to the comments eg: {{item.comment|markdown|restructuredtext}} as it adds another text formatting option? I almost added restructed text (my formatting) before i previewed it.

  18. 018 // Tim Jones // 04.10.2007 // 12:22 PM

    It’s pronounced “jango”, silent d.

  19. 019 // Jeff Croft // 04.10.2007 // 12:51 PM

    Tim, I’m pretty sure everyone here knows well how to pronounce it — but thanks anyway.

  20. 020 // Josh Ourisman // 09.15.2007 // 4:30 PM

    I currently working on rebuilding my site with Django. Right now I’m working on the templates, and attempting to get template inheritance to work. I have my skeleton template set up as ‘base.html’ and then another template (people.html) that starts with {% extends “base” %}. However, when I try and load the page it tells me ‘Template u’base’ cannot be extended, because it doesn’t exist’. In the Django docs it says to use {% extends “base.html” %}, but that doesn’t work either. Do I have to somehow explicitly reference base.html in my file or something like that? Currently I just have them in the same directory which I figured would be enough.

  21. 021 // Jeff Croft // 09.15.2007 // 4:53 PM

    Josh: In the current version of Django, the appropriate syntax is:

     {% extends "base.html" %}

    (In previous version of Django, you did not need the .html.)

    This assumes your base.html template is at the root of your TEMPLATE_DIRS settings in You do not need to reference base.html in your views at all.

  22. 022 // Joshua Blount // 11.28.2007 // 9:32 AM

    Just wanted to mention that I love how

    code looks on your site


  23. 023 // Milinda Lakmal // 07.14.2008 // 9:29 PM

    Thanks for this nice tutorial. I figured out most of the basic things about Django templates after reading this.

  24. 024 // Frédéric Hébert // 11.08.2008 // 11:18 AM

    Hi, and thanks a lot for these hints.

    I’m a beginner with Django, and I wondered if there is a way to a kind of fine tuning nested inheritance. As far as I can see, you actually can do things like that with Django:


    {% block content %}
       <p>base content</p>
       {% block sub_content_1 %}
       <p>base sub_content_1 bla bla</p>
       {% endblock sub_content_1 %}
       {% block sub_content_2 %}
       <p>base sub_content_2 bla bla</p>
       {% endblock sub_content_2 %}
       {% endblock content %}


    {% block content %}
        {{ block.parent }}
        {% block sub_content_2 %}
        <p>child sub_content_2 bla bla</p>
        {% endblock sub_content_2 %}
    {% endblock content %}

    to obtain something like that:

    <p>base content</p>

    base sub_content_1 bla bla

    child sub_content_2 bla bla

    but could we do something like this:


    {% block content %}
        {{ block.parent.content }}
        {% block sub_content_2 %}
        <p>child sub_content_2 bla bla</p>
        {% endblock sub_content_2 %}
        {{ block.parent.sub_content_1 }}
    {% endblock content %}

    to obtain:

    <p>base content</p>

    child sub_content_2 bla bla

    base sub_content_1 bla bla

  25. 025 // Joe // 01.19.2009 // 11:58 AM

    Is there anyway to do this sort of in reverse, without having a complex sequential inheritance?

    What I mean is I have a template which is fairly large as it displays section by section a break down of a XML configuration for an external application. What I wanted to do was break out each section into it’s own piece of html, purely for readabilities sake.

    What I find with django is if I want to do this using inheritance it seems I need to do something like

    base.html {% block section1 %} {% endblock %} {% block section2 %} {% endblock %} {% block section3 %} {% endblock %}

    section1.html {% extends base.html %} {% block section1 %} blah blah {% endblock %}

    section2.html {% extends section1.html %} {% block section1 %} blah blah {% endblock %}

    section3.html {% extends section2.html %} {% block section1 %} blah blah {% endblock %}

    But that is counter intuitive to someone else reading my code since really one section has very little to do with the previous section.

    Am I missing something, is there some other way to handle more complex inheritance?

  26. 026 // Alasdair // 02.06.2009 // 9:59 AM

    @Joe #29:

    the {{ include ‘filename.html’}} tag might be what you’re looking for.

  27. 027 // Dimitris // 08.01.2009 // 11:33 PM

    Thanks for the article. Very informative

  28. 028 // inoe // 08.14.2009 // 7:27 AM

    nice article :D. it helps me a lot. better than the django documentation.

  29. 029 // miki moore // 12.29.2009 // 8:20 PM

    The link for the intro (part1) is broken. The correct link is…

Tags for this entry
Links in this entry