Timmy O'Mahony
Timmy O'Mahony

Reputation: 53971

Overwriting a block within an `include`d template from an extended template

I have the following:

base.html

<html>
    {% include 'header.html' %}
    <div>
    {% block content %}Default Content{% endblock %}
    </div>
</html>

header.html

<header>
     {% block logo %}Logo 1{% endblock %}
</header>

homepage.html

{% extend 'base.html' %}
{% block logo %}Logo 2{% endblock %}
{% block content %}Yap Yap Yap{% endblock %}

Essentially, this doesn't work. When I render the homepage.html I get:

<html>
    <header>Logo 1</header>
    <div>Yap Yap Yap</div>
</html>

but If I move the code in header.html into base.html (i.e. get rid of the include altogether) it works ok. Can anyone explain why this is the case?

I have a feeling it has something to do with the included templates getting rendered after their parents have been rendered?

Upvotes: 16

Views: 6173

Answers (4)

Lars Ericson
Lars Ericson

Reputation: 2094

I had a similar problem. I have a filtered table template which is of form

{% extends 'base.html' %}
{% include 'filtered_table.html' %}

where filtered_table.html is:

{% load render_table from django_tables2 %}
<div class="panel-body" >
  <form method='GET'>
  <div class="search-form" style="border: 1px solid #000000; background-color:#a3ffaf; overflow: auto;">
{% block render_form %}
    {% for field in filter.form %}
         {{ field.errors }}
         {{ field.label_tag }} {{ field }}
    {% endfor %}
{% endblock %}
    <input type='submit' value='Filter' />
    |
    Displaying {{ filter.qs.count }} of {{ filter.queryset.count }} {{ object_name }}s.
    |
    <a href='{{ request.path }}' >Clear</a> <p>
  </div>

{% if table %}
    {% render_table table %}
{% endif %}

</form>

</div>

I may want to specially hand-craft the form, for example by spelling out each field like this:

{% block render_form %}
{{ filter.form.field1.errors }}
{{ filter.form.field1.label_tag }}
{{ filter.form.field1 }}
<p>

{{ filter.form.field2.errors }}
{{ filter.form.field2.label_tag }}
{{ filter.form.field2 }} 
{% endblock %}

Unfortunately, because I can't do "extends" twice, I can't get my base layout and customize the filtered table. So the ugly (because breaks HTML structure in half) way to do this is to simply define begin_filtered_table.html and end_filtered_table.html. Then in the customized case I have two includes wrapping the customization, and for the uncustomized case, filtered_form.html is defined like this:

{% include "begin_filtered_table.html" %}

    {% for field in filter.form %}
         {{ field.errors }}
         {{ field.label_tag }} {{ field }}
    {% endfor %}

{% include "end_filtered_table.html" %}

This solves the problem at the expense of being gross. It would be much easier just to allow multiple extends.

Upvotes: 2

caio
caio

Reputation: 1979

This is a known limitation that we hope be solved in a near future.

By the way, presuming that you have a more complex problem that you have mentioned, another work around for this is making header a block and than overriding this block with a new custom include.

base.html

<html>
    {% block header %}
        {% include 'header.html' %}
    {% endblock %}
    <div>
        {% block content %}Default Content{% endblock %}
    </div>
</html>

header.html

<header>
     {% block logo %}Logo 1{% endblock %}
</header>

homepage.html

{% extends 'base.html' %}

{% block header %}
    {% include 'homepage_header.html' %}
{% endblock %}

{% block content %}Yap Yap Yap{% endblock %}

homepage_header.html

{% extends 'header.html' %}

{% block logo %}Logo 2{% endblock %}

Upvotes: 6

Wesley
Wesley

Reputation: 2264

You cannot overwrite the logo from homepage.html because it's not defined in the base template itself.

The solution is, as you propose, to move the header.html code into base.html

Upvotes: 1

Timmy O&#39;Mahony
Timmy O&#39;Mahony

Reputation: 53971

from the docs

The include tag should be considered as an implementation of "render this subtemplate and include the HTML", not as "parse this subtemplate and include its contents as if it were part of the parent". This means that there is no shared state between included templates -- each include is a completely independent rendering process.

so the subtemplate (header.html) is getting fully rendered and inserted into the parent template (base.html), meaning there is no concept of the block for the child template (homepage.html) to overwrite

Upvotes: 14

Related Questions