I'm wondering if anyone knows how to deal with the following quirky template structure:
### base.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title> {% block title %} Title of the page {% endblock %} </title> </head> <body> <header> {% block header %} {% include "base/header.html" %} {% endblock header %} </header> {% block content %}{% endblock %} </body> </html>
### base/header.html <div id="menu-bar"> {% block nav %} {% include "base/nav.html" %} {% endblock %} </div>
### base/nav.html <nav id="menu"> <ul> <li> <a href="/profile/">My Profile</a> </li> <li> <a href="/favs/">My Favorites</a> </li> {% block extra-content %}{% endblock %} </ul> </nav>
And, the heart of the matter:
### app/somepage.html {% extends "base.html" %} {% block content %} <p>Content is overridden!</p> {% endblock %} {% block extra-content %} <p>This will not show up, though...</p> {% endblock %} {% block nav %} <p>Not even this.</p> {% endblock %}
The problem is when extending a template you can only override the blocks declared in the parent only, not any of its children.
I suppose I could make base.html a husk of empty unused nested blocks covering all future contingencies, but would even that override properly? And is that the only way?
If you're wondering why I have a bi-directional include/extends workflow around base.html, I have many sub-templates that I want to get used all across the project: Headers, footers, navs, sidebars, etc. They all will be consistant in structure across the entire site, but in many cases a whole subdivision of the site will only need a few of those sub-templates. My idea was to define the sub-templates under the templates/base folder, and have templates/base-type1.html, templates/base-type2.html, etc to extend in other places. Each type would only reference the sub-templates needed, and override them to place content as needed.
It seems to be little known that you can use the with
keyword with the include
to pass variables into the context of an included template - you can use it to specify includes in the included template:
# base.html <html> <body> {% block header %}{% include "header.html" %}{% endblock %} </body> </html> # header.html # some stuff here <div id="header"> <img src="logo.png"> {% include nav_tmpl|default:"navigation.html" %} </div> # special_page.html (uses other navigation) {% extends "base.html" %} {% block header %} {% include "header.html" with nav_tmpl="special_nav.html" %} # you might also want to wrap the include in an 'if' tag if you don't want anything # included here per default {% endblock %}
This approach saves you at least from having one additional file just for the purpose of overwriting a block. You can also use the with
keyword to pass a value through a bigger hierarchy of includes as well.
A terser variant to the solution proposed by @Bernhard Vallant:
# base.html <html> <body> {% block header %}{% include "header.html" %}{% endblock %} </body> </html> # header.html # some stuff here <div id="header"> <img src="logo.png"> {% include nav_tmpl|default:"navigation.html" %} </div> # special_page.html (uses other navigation) {% extends "base.html" %} {% block header %} {% with nav_tmpl="special_nav.html" %} {{ block.super }} {% endwith %} {% endblock %}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With