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.