Create reusable templates

Templates tend to have common sections that are equally used across multiple instances. For example, the header and footer sections on all templates rarely changes, whether a project has five or one hundred templates. Other template sections like menus and advertisements, also fall into this category of content that's constant across multiple templates. All of this can lead to repetition over multiple templates, which can be avoided by creating reusable templates.

With reusable Django templates you can define common sections on separate templates and reuse them inside other templates. This process makes it easy to create and manage a project's templates because a single template update takes effect on all templates.

Reusable Django templates also allow you to define page blocks to override content on a page by page basis. This process makes a project's templates more modular because you define top level blocks to establish the overall layout and define content on a page by page basis.

Lets take the first step toward building reusable Django templates exploring the Django built-in {% block %} tag. Listing 3-10 illustrates the first lines of a template called base.html with several {% block %} tags.

Listing 3-10. Django template with {% block %} tags

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>{% block title%}Default title{% endblock title %}</title>
    <meta name="description" content="{% block metadescription%}{% endblock metadescription %}">
    <meta name="keywords" content="{% block metakeywords%}{% endblock metakeywords %}">

Notice the syntax {% block <name>%}{% endblock <name> %} in listing 3-10. Each {% block %} tag has a reference name. The reference name is used by other Django templates to override the content for each block.

For example, the {% block title %} tag within the HTML <title> tags defines a web page title. If another template reuses the template in listing 3-10, it can define its own web page title by overriding the title block. If a block is not overridden on a template, the block receives the default content within the block. For the title block the default content is Default title, for the metadescription and metakeywords blocks the default content is an empty string.

The same mechanism illustrated in listing 3-10 can be used to define any number of blocks (e.g. content, menu, header, footer). It's worth mentioning the <name> argument of {% endblock <name> %} is optional and it's valid to just use {% endblock %} to close a block statement, however, the former technique makes it clearer where a block statement ends which is specially helpful when a template has multiple blocks.

Although it's possible to call the template in listing 3-10 directly by a Django view method or url request, the purpose of this kind of template is to use it as a base template for other templates. To reuse a Django template you use the Django built-in {% extends %} tag.

The {% extends %} tag uses the syntax {% extends <name> %} to reuse the layout of another template. This means that in order to reuse the layout in listing 3-10 defined in a file base.html, you use the syntax {% extends "base.html" %}. In addition, if you use the {% extends %} tag it has to be the first definition in Django template, as illustrated in listing 3-11.

Listing 3-11 Django template with {% extends %} and {% block %} tag

{% extends "base.html" %}
{% block title %}Coffeehouse home page{% endblock title %} 
Tip In an {% extend <name> %} tag statement, the <name> value can also use a relative path (e.g. "../base.html"), as well as a variable passed by a view that can be a string (e.g. "master.html") or Template object loaded in the view.

Notice in listing 3-11 how the first template statement is {% extends "base.html" %}. In addition, notice how listing 3-11 defines the {% block title %} tag with the content Coffeehouse home page. The block in listing 3-11 overrides the title block from the base.html template. So where are the HTML <title> tags in listing 3-11 ? There aren't any and you don't need them. Django automatically reuses the layout from the base.html template and substitutes the blocks content where necessary.

Django templates that reuse other templates tend to have limited layout elements (e.g. HTML tags) and more Django block statements to override content. This is beneficial because as I outlined previously, it lets you establish the overall layout once and define content on a page by page basis.

The re-usability of Django templates can occur multiple times. For example, you can have templates A, B and C, where B requires to reuse A, but C requires to reuse parts of B. The only difference is template C needs to use the {% extends "B" %} tag instead of the {% extends "A"%} tag. But since template B reuses A, template C also has access to the same elements in template A.

When reusing Django templates, it's also possible to access the block content from a parent template. Django exposes the block content from a parent template through the reference block.super. Listing 3-12 illustrates three templates that show this mechanism for a block containing web page paths or 'breadcrumbs'.

Listing 3-12 Django templates use of {{block.super}} with three reusable templates

# base.html template 
<p>{% block breadcrumb %}Home{% endblock breadcrumb %}</p>


# index.html template
{% extends "base.html" %} 
{% block breadcrumb %}Main{% endblock breadcrumb %} 


# detail.html template
{% extends "index.html" %} 
{% block breadcrumb %} {{block.super}} : Detail {% endblock breadcrumb %} 

The base.html template in listing 3-12 defines the breadcrumb block with a default value of Home. Next, the index.html template reuses the base.html template and overrides the breadcrumb block with a value of Main. Finally, the detail.html template reuses the index.html template and overrides the breadcrumb block value. However, notice the {{block.super}} statement in the final block override. Since {{block.super}} is inside the breadcrumb block, {{block.super}} tells Django to get the content from the parent template block.

Another re-usability functionality in Django templates is the inclusion of a Django template inside another Django template. Django supports this functionality through the {% include %} tag.

The {% include %} tag expects a template argument -- similar to the {% extend %} tag -- which can be either a hard-coded string reference (e.g. {% include "footer.html" %} ), a relative path to a template (e.g. {% include "../header.html" %}) or a variable passed by a view that can be a string or Template object loaded in the view. It's worth pointing that when using a variable with the {% include %} tag, the variable value can be either: a string representing a template name or an iterable (e.g. tuple, list, dictionary) representing multiple template names, in the latter case the first template to be found in the iterable is used. Note that if the iterable is a dictionary, the keys are used to find a matching template name.

Templates declared as part of {% include %} tags are made aware of context variables in the template that declares them. This means if template A uses the {% include "footer.html" %} tag, template A variables are automatically made available to the footer.html template.

Inclusively, it's possible to explicitly provide context variables to {% include %} statements using the with keyword. For example, the statement {% include "footer.html" with year="2013" %} makes the year variable accessible inside the footer.html template. The {% include %} tag also supports the ability to pass multiple variables using the with notation (e.g. {% include "footer.html" with year="2013" copyright="Creative Commons" %}).

Finally, if you want templates declared as part of {% include %} tags to have restricted access to context variables from the template that declares them, you can use the only keyword. For example, if template B uses the {% include "footer.html" with year="2013" only %} statement, the footer.html template only gets access to the year variable, irrespective of the variables available in template B. Similarly, the {% include "footer.html" only %} statement restricts the footer.html template to no variables, irrespective of the variables available in the template that uses the statement.