DEV Community

DoriDoro
DoriDoro

Posted on

Understanding Django template inheritance

Introduction

As the Django documentation says:
The most powerful - and therefore most complex - part of Django's template engine is template inheritance. Template inheritance allows you to create a base "skeleton" template that contains all the common elements of your site, and defines blocks that child templates can override.

To show you some specifics about the Django template and what is important to understand, let's create an example.

# base.html

AAA
{% block foo %}{% endblock %}
{% block bar %}BBB{% endblock %}
CCC
Enter fullscreen mode Exit fullscreen mode
# b.html

{% extends "base.html" %}

{% block foo %}
  DDD
  {% block bar %}
    EEE
  {% endblock %}
  FFF
{% endblock %}
Enter fullscreen mode Exit fullscreen mode
# c.html

{% extends "base.html" %}

{% block bar %}
  {{ block.super }}
  GGG
{% endblock %}

{% if False %}
  HHH
  {% block foo %}
    III
  {% endblock %}
{% endif %}

JJJ
Enter fullscreen mode Exit fullscreen mode

Results:

Here is the result of using render_to_string("b.html") and render_to_string("c.html") in a Django view, for example:

  • render_to_string("b.html"):
AAA
{% block foo %}
  DDD
  {% block bar %}
    EEE
  {% endblock %}
  FFF
{% endblock %}
{% block bar %}
  EEE
{% endblock %}
CCC
Enter fullscreen mode Exit fullscreen mode
  • render_to_string("c.html"):
AAA
{% block foo %}
  III
{% endblock %}
{% block bar %}
  BBB
  GGG
{% endblock %}
CCC
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • render_to_string("b.html"):
# base.html

AAA
{% block foo %}{% endblock %}
{% block bar %}BBB{% endblock %}
CCC
Enter fullscreen mode Exit fullscreen mode
# b.html

{% extends "base.html" %}

{% block foo %}
  DDD
  {% block bar %}
    EEE
  {% endblock %}
  FFF
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

{% extends "base.html" %}: The extends block is the key to telling the template engine that this template is "extended" from another template. The template system will first locates the parent template - in this case "base.html".

When the template engine evaluates the parent template ("base.html"), it notices two blocks and immediately replaces them with the content of the child template blocks.

This is what it will look like:

# base.html

AAA
{% block foo %}   # {% block foo %}...
  DDD
  {% block bar %}
    EEE
  {% endblock %}
  FFF
{% endblock %}  # ... {% endblock %}

{% block bar %}  # {% block bar %} ...
  EEE
{% endblock %}  # ... {% endblock %}
CCC
Enter fullscreen mode Exit fullscreen mode

The template engine will replace the {% block foo %} in the parent template ("base.html") with the entire {% block foo %} in the child template. It does not matter that there is a {% block bar %} inside the {% block foo %}, the whole block will be replaced.

Because there is a {% block bar %} even if it is inside another block, this {% block bar %} will replace the {% block bar %} in the parent template ("base.html").

  • render_to_string("c.html"):
# base.html

AAA
{% block foo %}{% endblock %}
{% block bar %}BBB{% endblock %}
CCC
Enter fullscreen mode Exit fullscreen mode
# c.html

{% extends "base.html" %}

{% block bar %}
  {{ block.super }}
  GGG
{% endblock %}

{% if False %}
  HHH
  {% block foo %}
    III
  {% endblock %}
{% endif %}

JJJ
Enter fullscreen mode Exit fullscreen mode

As in the previous example, the "extends" block tells the template engine to find a parent template. It will then evaluate the blocks within the child template. There are different things that are important in this example:

  • {{ block.super }}: If the parent template already contains variables or content, {{block.super }} gets the parent's content into the child template.

  • block inside if-statement: The if statement is False but the template engine will overwrite the {% block foo %} anyway. The key phrase in Django's template inheritance documentation for the above code is:
    {% block %} tags are evaluated first. That’s why the content of a block is always overridden, regardless of the truthiness of surrounding tags. For example, this template will always override the content of the title block.
    The {% block %} will be evaluated even it is wrapped inside of a if statement which is False. Every mentioned {% block %} will be displayed.

  • content: JJJ: The content JJJ is outside the block, after the {% endblock %}, so it is ignored.

This is what it will look like:

# base.html

AAA
{% block foo %}  # {% block foo %}...
  III
{% endblock %}  # ...{% endblock %}
{% block bar %}  #  {% block bar %}...
  BBB  # BBB (because {% block.super %})
  GGG
{% endblock %}  # ...{% endblock %}
CCC
Enter fullscreen mode Exit fullscreen mode

Top comments (0)