Our template examples so far have been tiny HTML snippets, but in the real world, you’ll be using Django’s template system to create entire HTML pages. This leads to a common Web development problem: across a Web site, how does one reduce the duplication and redundancy of common page areas, such as site-wide navigation?
A classic way of solving this problem is to use server-side includes, directives you can embed within your HTML pages to “include” one Web page inside another. Indeed, Django supports that approach, with the {% include %} template tag just described. But the preferred way of solving this problem with Django is to use a more elegant strategy called template inheritance.
In essence, template inheritance lets you build a base “skeleton” template that contains all the common parts of your site and defines “blocks” that child templates can override.
Let’s see an example of this by creating a more complete template for our current_datetime view, by editing the current_datetime.html file:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>The current time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>It is now {{ current_date }}.</p> <hr> <p>Thanks for visiting my site.</p> </body> </html>
That looks just fine, but what happens when we want to create a template for another view—say, the hours_ahead view from Chapter 3? If we want again to make a nice, valid, full HTML template, we’d create something like:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Future time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> <hr> <p>Thanks for visiting my site.</p> </body> </html>
Clearly, we’ve just duplicated a lot of HTML. Imagine if we had a more typical site, including a navigation bar, a few style sheets, perhaps some JavaScript—we’d end up putting all sorts of redundant HTML into each template.
The server-side include solution to this problem is to factor out the common bits in both templates and save them in separate template snippets, which are then included in each template. Perhaps you’d store the top bit of the template in a file called header.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en"> <head> And perhaps you’d store the bottom bit in a file called footer.html: <hr> <p>Thanks for visiting my site.</p> </body> </html>
With an include-based strategy, headers and footers are easy. It’s the middle ground that’s messy. In this example, both pages feature a title— <h1>My helpful timestamp site</h1>—but that title can’t fit into header.html because the <title> on both pages is different. If we included the <h1> in the header, we’d have to include the <title>, which wouldn’t allow us to customize it per page. See where this is going?
Django’s template inheritance system solves these problems. You can think of it as an “inside-out” version of server-side includes. Instead of defining the snippets that are common, you define the snippets that are different.
The first step is to define a base template—a skeleton of your page that child templates will later fill in. Here’s a base template for our ongoing example:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>{% block title %}{% endblock %}</title> </head> <body> <h1>My helpful timestamp site</h1> {% block content %}{% endblock %} {% block footer %} <hr> <p>Thanks for visiting my site.</p> {% endblock %} </body> </html>
This template, which we’ll call base.html, defines a simple HTML skeleton document that we’ll use for all the pages on the site.
It’s the job of child templates to override, or add to, or leave alone the contents of the blocks. (If you’re following along at home, save this file to your template directory.)
We’re using a template tag here that you haven’t seen before: the {% block %} tag. All the {% block %} tags do is tell the template engine that a child template may override those portions of the template.
Now that we have this base template, we can modify our existing current_datetime.html template to use it:
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}
While we’re at it, let’s create a template for the hours_ahead view from Chapter 3. (If you’re following along with code, we’ll leave it up to you to change hours_ahead to use the template system.) Here’s what that would look like:
{% extends "base.html" %}
{% block title %}Future time{% endblock %}
{% block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{% endblock %}
Isn’t this beautiful? Each template contains only the code that’s unique to that template. No redundancy needed. If you need to make a site-wide design change, just make the change to base.html, and all of the other templates will immediately reflect the change.
Here’s how it works. When you load the template current_datetime.html, the template engine sees the {% extends %} tag, noting that this template is a child template. The engine immediately loads the parent template—in this case, base.html.
At that point, the template engine notices the three {% block %} tags in base.html and replaces those blocks with the contents of the child template. So, the title we’ve defined in {% block title %} will be used, as will the {% block content %}.
Note that since the child template doesn’t define the footer block, the template system uses the value from the parent template instead. Content within a {% block %} tag in a parent template is always used as a fallback.
Inheritance doesn’t affect the way the context works, and you can use as many levels of inheritance as needed. One common way of using inheritance is the following three-level approach:
- Create a html template that holds the main look and feel of your site. This is the stuff that rarely, if ever, changes.
- Create a html template for each “section” of your site (e.g., base_photos.html and base_forum.html). These templates extend base.html and include section-specific styles/design.
- Create individual templates for each type of page, such as a forum page or a photo gallery. These templates extend the appropriate section template.
This approach maximizes code reuse and makes it easy to add items to shared areas, such as section-wide navigation. Here are some tips for working with template inheritance:
- If you use {% extends %} in a template, it must be the first template tag in that template. Otherwise, template inheritance won’t work.
- Generally, the more {% block %} tags in your base templates, the better. Remember, child templates don’t have to define all parent blocks, so you can fill in reasonable defaults in a number of blocks, and then define only the ones you need in the child templates. It’s better to have more hooks than fewer hooks.
- If you find yourself duplicating code in a number of templates, it probably means you should move that code to a {% block %} in a parent template.
- If you need to get the content of the block from the parent template, the {{ super }} variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it.
- You may not define multiple {% block %} tags with the same name in the same template. This limitation exists because a block tag works in “both” directions. That is, a block tag doesn’t just provide a hole to fill, it also defines the content that fills the hole in the parent. If there were two similarly named {% block %} tags in a template, that template’s parent wouldn’t know which one of the blocks’ content to use.
- The template name you pass to {% extends %} is loaded using the same method that get_template() That is, the template name is appended to your TEMPLATE_DIRS setting.
- In most cases, the argument to {% extends %} will be a string, but it can also be a variable, if you don’t know the name of the parent template until runtime. This lets you do some cool, dynamic stuff.