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 {{ entry.author }}, 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.

Basic blog HTML

<html>
  <head>
    <link href="base.css" rel="stylesheet" />
    <title>This is my blog on Django</title>
  </head>
  <body>
    <div id="header">
      <h1>This is my Django Blog!</h1>
      <ul id="main-nav">
        <li><a href="/">Home</a></li>
        <li><a href="/blog/archives">Archives</a></li>
        <li><a href="/about-me">About Me</a></li>
      </ul>
    </div>
    <div id="content"></div>
    <div id="sidebar">
      <h3> Blogroll</h3>
      <ul id="blogroll">
        <li><a href="http://somesite.com">Someone's Blog</a></li>
        <li><a href="http://somesite2.com">Someone Else's Blog</a></li>
        <li><a href="http://somesite3.com">Yet Someone's Else's Blog</a></li>
      </ul>
    </div>
  </body>
</html>

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:

Basic blog with blocks Django Template

<html>
  <head>
    <link href="base.css" rel="stylesheet" />
    <title>My Blog: {% block title %}Generic Page{% endblock %}</title>
    {% block extrahead %}{% endblock %}
  </head>
  <body>
    <div id="header">
      <h1>This is my Django Blog!</h1>
      <ul id="main-nav">
        <li><a href="/">Home</a></li>
        <li><a href="/blog/archives">Archives</a></li>
        <li><a href="/about-me">About Me</a></li>
      </ul>
    </div>
    <div id="content">
      {% block content %}{% endblock %}
    </div>
    <div id="sidebar">
      {% block sidebar %}
        <h3> Blogroll</h3>
        <ul id="blogroll">
          <li><a href="http://somesite.com">Someone's Blog</a></li>
          <li><a href="http://somesite2.com">Someone Else's Blog</a></li>
          <li><a href="http://somesite3.com">Yet Someone's Else's Blog</a></li>
        </ul>
      {% endblock %}
    </div>
  </body>
</html>

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.

entry.html Django Template

{% extends "base" %}

{% block title %}
    {{ entry.title}}
{% endblock %}

{% block content %}
    <h2>{{ entry.title}}</h2>
    <h3>By {{ entry.author}}</h3>
    <p>{{ entry.body }}</p>
{% endblock %}

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:

Output of entry_detail.html HTML

<html>
  <head>
    <link href="base.css" rel="stylesheet" />
    <title>My Blog: First Entry</title>
  </head>
  <body>
    <div id="header">
      <h1>This is my Django Blog!</h1>
      <ul id="main-nav">
        <li><a href="/">Home</a></li>
        <li><a href="/blog/archives">Archives</a></li>
        <li><a href="/about-me">About Me</a></li>i>
      </ul>
    </div>
    <div id="content">
      <h2>First Entry</h2>
      <h3>By Jeff Croft</h3>
      <p>This is the first entry in my new Django-powered blog!</p>
    </div>
    <div id="sidebar">
      <h3> Blogroll</h3>
      <ul id="blogroll">
        <li><a href="http://somesite.com">Someone's Blog</a></li>
        <li><a href="http://somesite2.com">Someone Else's Blog</a></li>
        <li><a href="http://somesite3.com">Yet Someone's Else's Blog</a></li>
      </ul>
    </div>
  </body>
</html>

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:

entry_music.html Django Template

{% extends "entry" %}

{% block extrahead %}
    <link href="music.css" rel="stylesheet">
{% endblock %}

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

Output of entry_music.html HTML

<html>
  <head>
    <link href="base.css" rel="stylesheet" />
    <title>My Blog: First Entry</title>
    <link href="music.css" rel="stylesheet" />
  </head>
  <body>
    <div id="header">
      <ul id="main-nav">
        <li><a href="/">Home</a></li>
        <li><a href="/blog/archives">Archives</a></li>
        <li><a href="/about-me">About Me</a></li>
      </ul>
    </div>
    <div id="content">
      <h2>First Entry</h2>
      <h3>By Jeff Croft</h3>
      <p>This is the first entry in my new Django-powered blog!</p>
    </div>
    <div id="sidebar">
      <h3> Blogroll</h3>
      <ul id="blogroll">
        <li><a href="http://somesite.com">Someone's Blog</a></li>
        <li><a href="http://somesite2.com">Someone Else's Blog</a></li>
        <li><a href="http://somesite3.com">Yet Someone's Else's Blog</a></li>
      </ul>
    </div>
  </body>
</html>

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:

entry_music.html Django Template

{% extends "entry" %}

{% block extrahead %}
  <link href="music.css" rel="stylesheet" />
{% endblock %}

{% block sidebar %}
  {{ block.super }}
  <h3>What I'm listing to</h3>
  <ul>
    <li><a href="http://bandssite.com">Some great band</a></li>
    <li><a href="http://bandssite2.com">Some other great band</a></li>
  </ul>
{% endblock %}

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.

Comments

  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

    Justin:

    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:

    http://www.djangoproject.com/documentation/tutorial2/

    Michael:

    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 irc.freenode.net 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: http://www.djangoproject.com/community/ 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

    Luke-

    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

    jeffcroft.com/blog/archives/2006/02/django_template.php
    

    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 http://www.djangoproject.com/documentation/db_api 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 views.py 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 settings.py. 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

    Thanks!

  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 // ламинат // 08.24.2008 // 5:24 PM

    9cThank’s.1l I compleatly agree with last post. ati паркет 2m

  25. 025 // ламинат // 08.24.2008 // 5:37 PM

    8zThank’s for greate post.5s I compleatly disagree with last post . mrm паркет 9g

  26. 026 // ламинат // 08.24.2008 // 6:08 PM

    6kGood idea.9y I compleatly agree with last post. vcq ламинат 7b

  27. 027 // ламинат // 08.24.2008 // 7:13 PM

    9sGood idea.9e I compleatly disagree with last post . iio ламинированный паркет 7l

Post your comment