问题
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.
回答1:
You can solve this by extending your currently-included templates, then including the extension instead of the the currently-included base template.
回答2:
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.
回答3:
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 %}
来源:https://stackoverflow.com/questions/9996428/django-templates-overriding-blocks-of-included-children-templates-through-an-ex