Reputation: 34690
Is there a way to have content blocks with the same name?
base.html:
This is the template with the main layout.
<html>
...
{% block content %}
{% endblock %}
...
</html>
base_side_left.html:
This is the template with the main layout + sidebar on the left.
{% extends 'base.html' %}
{% block content %}
<div class='sidebar'>
</div>
{% block content %}
//This doesn't work because you can't have blocks with the same name//
{% endblock %}
{% endblock
I have a few reason why I am asking this:
I got two solutions for this which I don't like because they ain't DRY:
If this isn't possible with Django Template can I do something like this with an other templating engine?
Small update:
So what I want to do is to be able to move the templates around in the template tree without to much hassle. It's not possible though without coming up with smart names for my content blocks but I thought I add this pretty diagram anyways.
Upvotes: 2
Views: 4801
Reputation: 42845
No, you can't. From the Django docs on template inheritance:
you can't define multiple
{% block %}
tags with the same name in the same template. This limitation exists because a block tag works in "both" directions. That is, a block tag doesn't just provide a hole to fill -- it also defines the content that fills the hole in the parent. If there were two similarly-named{% block %}
tags in a template, that template's parent wouldn't know which one of the blocks' content to use.
I'm not clear on why you want to do this.
It's easy to change the parent of a page without having to change the name of the content blocks.
There's only one {% block %}
tag with a given name, and there's only one {% extends %}
tag as well. I don't see any difference in difficulty.
I don't have to come up with names for my blocks. Like content-content, sidebar-content, etc
Anyone maintaining your code will quickly lose track of which content
block is effective and get confused. Besides, the names should have something to do with what the {% block %}
is supposed to do. So I'm wondering why you'd have two templates, one including another, with blocks that are exactly the same.
Another point from the docs:
If you find yourself duplicating content in a number of templates, it probably means you should move that content to a {% block %} in a parent template.
This lets you make the duplicated markup the default, and you can override it in those places where needed.
This may be helpful, too:
If you need to get the content of the block from the parent template, the
{{ block.super }}
variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using{{ block.super }}
will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.
From what I can tell, this is probably your best choice:
Make the sidebar a partial and include it in the templates you need.
How is this not DRY? You have to repeat the {% include %}
tag?
I think there's a better design solution that would work for you, but you haven't given enough info on what you're trying to accomplish for me to help further.
EDIT: Looking at your example, you can do all that with a single template. CSS will take care of you here.
page_template.html:
<!DOCTYPE html PUBLIC -- ... -->
<html>
<head>
<!-- ... other header fields ... -->
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<base href="{{ host }}{{ root }}{{ path }}" />
<title>{% block title %}Untitled{% endblock %}</title>
<link rel="icon" type="image/png"
href="{{ root }}static/images/favicon.png" />
<link rel="stylesheet" type="text/css"
href="{{ root }}static/css/general.css" />
<!-- other header fields here -->
{% block head %}{% endblock %}
</head>
<body class="{% block page_class %}no_sidebar{% endblock %}">
<div id="page_header">
<!-- page heading here -->
</div>
<div id="sidebar">
{% block sidebar %}<!-- default sidebar here -->{% endblock %}
</div>
<div id="banner">
{% block banner %}{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
general.css:
body.no_sidebar div#sidebar,
div#banner
{
display: none;
}
div#sidebar
{
width: 20%;
}
body.with_sidebar div#sidebar
{
float: left;
}
body.with_banner div#banner
{
display: block;
}
body.right_sidebar div#sidebar
{
float: right;
}
Then your pages just look like, in the order of your examples:
plain_old_page.html:
{% extends base.html %}
{% block content %}
<!-- content goes here -->
{% endblock %}
page_with_left_sidebar.html:
{% extends base.html %}
{% block page_class %}with_sidebar{% endblock %}
{% block sidebar %}
<!-- sidebar goes here, if different from default -->
<!-- otherwise omit this section -->
{% endblock %}
{% block content %}
<!-- content goes here -->
{% endblock %}
page_with_left_sidebar_and_banner.html:
{% extends base.html %}
{% block page_class %}with_sidebar with_banner{% endblock %}
{% block sidebar %}
<!-- sidebar goes here, if different from default -->
<!-- otherwise omit this section -->
{% endblock %}
{% block banner %}
<!-- banner goes here -->
{% endblock %}
{% block content %}
<!-- content goes here -->
{% endblock %}
page_with_right_sidebar.html:
{% extends base.html %}
{% block page_class %}right_sidebar{% endblock %}
{% block sidebar %}
<!-- sidebar goes here, if different from default -->
<!-- otherwise omit this section -->
{% endblock %}
{% block content %}
<!-- content goes here -->
{% endblock %}
Upvotes: 5