[Fixed]-Nested django templates

15👍

the extends template tag can take a variable argument.

so:

base.html
    {% block content %}
        <p>BASE</p>
    {% endblock %}

parent.html
    {% extends "base.html" %}

    {% block content %}
        {{ block.super }}
        <p>PARENT</p>
    {% endblock %}

foo.html
    {% extends ext_templ %}

    {% block content %}
        {{ block.super }}
        <p>FOO</p>
    {% endblock %}

using base:

return render_to_response('foo.html', {'ext_templ':'base.html'})

gives you:

<p>BASE</p>
<p>FOO</p>

using parent:

return render_to_response('foo.html', {'ext_templ':'parent.html'})

gives you:

<p>BASE</p>
<p>PARENT</p>
<p>FOO</p>

edit:

one way around this problem to get nested blocks is:

base.html
    {% block content %}
        {% block top %}
            <p>BASE START</p>
        {% endblock %}

        {% block bot %}
            <p>BASE END</p>
        {% endblock %}
    {% endblock %}


parent.html
    {% extends "base.html" %}

    {% block top %}
        {{ block.super }}
        <p>PARENT</p>
    {% endblock %}

    {% block bot %}
        <p>PARENT</p>
        {{ block.super }}
    {% endblock %}

foo.html
    {% extends ext_templ %}

    {% block top %}
        {{ block.super }}
        <p>FOO</p>
    {% endblock %}

    {% block bot %}
        <p>FOO END</p>
        {{ block.super }}
    {% endblock %}

The other method that i can think of is to wrap the blocks with an {% if ext_templ == 'parent.html' %} tag but that doesn’t seem very dry. I’m curious to see other peoples response to nested blocks as well.

👤dting

2👍

  1. base.html
{% block content %}
  <p>Grand Parent file</p>
{% endblock %}
  1. parent.html
{% extends 'base.html' %}

{% block content %}
    {% include 'grandchild1.html' %}
    {% include 'grandchild2.html' %}
{% endblock %}

3.1. grandchild1.html

<div>Hello I'm grandchild 1</div>

3.2 grandchild1.html

<div>Hello I'm grandchild 2</div>

This way you can nest upto any level. write each components in sections in seperate .html files.
Include them to parent.html or to any other files.

0👍

I had three templates: gparent, parent, and gchild. Then I tested gparent and gchild as follows:

gparent had the following block hn tag. gchild extends gparent. There is no reference to parent.

{% block hn %}              
Can you see me?     # 1  naked text in the html, treated as a string.
{{  "No, I cant see you." }}    # 2 A string literal in the variable template brace.
{% endblock hn %}

Both of these lines between the tags showed up on the child on screen. When the latter was not a string, Django threw a parsing error. That is because inside the double curly braces, Django is expecting a variable, or something like this string literal that it can evaluate.

When I added a block hn and this content to gchild, gchild’s block hn content is all I saw.

{% block hn %}
Now I have my own hn block                      
{% endblock hn %}
                            

Then I repeated this test, leaving gchild’s block hn in place, but taking away the content:

{% block hn %}          
{% endblock hn %}                                   

An empty, but present block hn on gchild blocked out (overrode) gparent’s block hn content.

For this next test, I inserted parent between gparent and gchild. Now parent extends gparent, and gchild extends parent.

{%  block metadata %}
{{ "You must eat your metadata to grow big and strong" }}
{% endblock metadata %}

Parent now has this block metadata tag, which is present in neither gparent nor gchild.
This content did not display.

Next I nested block metadata inside block hn on parent. gparent still has the two strings we tested from block hn a moment ago. gchild has an empty block hn.

As before, nothing displayed.

I will now remove block hn from gchild:

You must eat your metadata to grow big and strong

So, you can add a new block tag that is not present in an earlier template generation, so long as it is fully nested within an available block that the ancestor does define.

The sandwich generation will then pass that new tag and its content along to the child, which will display it if the child does not block (override) it.

Remember that the docs describe the content between the tags as a hole to be filled. If the child does not have the tag, the hole gets filled by the parent. This is what makes the parent’s content the default. This is also why most base templates contain the header, footer, navigation, and styling you want throughout the site. But with the same tag on the child, the child is filling the hole itself. Again, this is why a child can have its own block title tag, even though it is nested inside the html , which is typically inside the parent block header, or whatever you choose to call it.

I really struggled with this when I first learned Django, because I always wanted to do crazy stuff like

{% block first %}
{% block second %}
{% endblock first %}
{% endblock second %}

That will not work anywhere.

Leave a comment