Django: nested content blocks with the same name - django

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:
It's easy to change the parent of a page without having to change the name of the content blocks.
I don't have to come up with names for my blocks. Like content-content, sidebar-content, etc
I got two solutions for this which I don't like because they ain't DRY:
Make the sidebar a partial and include it in the templates you need.
Add everything to the base template and overwrite those blocks you don't need.
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.

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 %}

Related

Is there a way to construct pages with components

I am familiar with the concept of extends and include with django templates.
However, I am trying to build up pages with components (which relates more to the "include" approach). Unfortunately, some elements on a page should be added in the header of the page (e.g. stylesheets) and some should be added at the end of the page (e.g. scripts).
Is there a way to declare blocks (e.g. {% block extraheaders %}<link...>{% endblock %}) in the included files so they are placed in the correct region of the page?
Perhaps you are looking for the following setup:
<!-- base.html -->
<html>
<head>
{% block css %}
<link href="/css/bootstrap.css">
<link href="/css/base.css">
{% endblock %}
</head>
<body>
{% block content %}{% endblock %}
{% block js %}
<script src="/js/jquery.js"></script>
<script src="/js/bootstrap.js"></script>
<script src="/js/base.js"></script>
{% endblock %}
</body>
</html>
{% extends base %}
{% block css %}
{{ block.super }}
<link href="/css/home-page.css" />
{% endblock %}
{% block content %}
<h1>Hello, World!</h1>
{% endblock %}
{% block js %}
{{ block.super }}
<link href="/js/home-page.js" />
{% endblock %}
...with the main point being that we can use {{ block.super }} to place specific resources into a parent template's blocks through inheritance.

Skip a level with {{ block.super }}

I have a 3rd party app that defines a bunch of templates (somewhat similar to how django-admin works). The base template defines a block with some content:
base.html:
<!doctype HTML>
<html><head>
<!-- blah blah -->
{% block very_kewl %}
<marquee><b><i><u>this is very kewl</marquee></b></i></u>
<!-- disclaimer: this is not valid HTML! -->
{% endblock very_kewl %}
</html>
Then a child template clears the block:
actual_page.html:
{% extends 'base.html' %}
{# very many other stuff, part 1 #}
{% block very_kewl %}{% endblock %}
{# very many other stuff, part 2 #}
What I want to achieve is to keep the "very kewl" content on the page.
An approach that works is to simply copy the entire actual_page.html into the project template dir and omit the line {% block very_kewl %}{% endblock %}. This works, but the downside is that I also have to repeat all the other parts of the template, some of which are likely to change in the future.
So the question is how can I show that "very kewl" content from the base template without also repeating all the other stuff in the actual_page.html?
Ideally, I would be able to do something like this, but of course, this doesn't work:
project_templates/actual_page.html:
{% extends 'actual_page.html' %}
{% block very_kewl %}{{ block.super.super }}{% endblock %}
Why not keep the HTML used in the base template's block as a separate template?
project_template/partials/very_kewl.html
<marquee><b><i><u>this is very kewl</marquee></b></i></u>
<!-- disclaimer: this is not valid HTML! -->
Now, just include it wherever the HTML needs to be used.
project_template/base.html
<!doctype HTML>
<html><head>
<!-- blah blah -->
{% block very_kewl %}
{% include 'partials/very_kewl.html' %}
{% endblock very_kewl %}
</html>
And in the grandchild project_templates/actual_page.html
{% extends 'actual_page.html' %}
{% block very_kewl %}{% include 'partials/very_kewl.html' %}{% endblock %}
So even at some point the block gets cleared up, the childs of that template can simply include the required HTML.

Is it possible to use a block tag ({% block %}) from base html template two or more times in derived html file in Django

I want to be able to reuse the same block tag multiple times in derived html.
something like:
base.html
<body>
{% block panel %}
# some basic panel structure inside this block
{% endblock %}
</body>
derived.html
{% extends base.html %}
--first panel
<div class="col">
{% block panel %}
# override things like panel header
{% endblock %}
</div>
--second panel
<div class="col">
{% block panel %}
# again override some panel stuff from base template
{% endblock %}
</div>
Is there anyway i can achieve this in Django?
No, it will result in template syntax error. The best you can do is to include as many block tags as you require in base and reuse them. Or you can even loop the blocks in base.
I haven't tested it out, but theoretically it should work. In your base, create a loop block, in below example it creates 6 blocks, block content1..... content6
{% for i in '123456' %}
{% block content{{i}} %}
Foo
{% endblock content{{i}} %}
{% endfor %}
No, you can not. The best way to do it is, assign each block for each panel or if you have multipanel then run the loop for the block.
In your current case (i assuming two panel in single derived file) it would be like this-
base.html
<body>
{% block content %}
<!-- all your panels -->
{% endblock %}
</body>
derived.html
{% extends "base.html" %}
{% block content %}
 <div class="col">
<!-- First panel -->
<!-- Second panel -->
</div>
{% endblock %}
The block is just for reducing the redundant work which unique to each extended file. so you can only referred it to single time in any extended file.

django template extends not working

This is my base.html
<!DOCTYPE html>
<head>
<title> My Site </title>
</head>
<body>
<div id="wrapper">
<!-- HEADER START -->
{% block nav %} {% endblock %}
{% block index %} {% endblock %}
</div>
</body>
</html>
this is my nav.html
{% extends "base.html" %}
{% block nav %}
<div id="header">
<div class="inner">
<div class="nav">
<ul>
<li class="current">Home</li>
<li>About</li>
<li>Blog</li>
<li>Contact</li>
</ul>
</div>
<div class="clear"></div>
</div><!-- .inner end -->
</div><!-- #header end -->
<!-- HEADER END -->
{% endblock %}
this is my index.html
{% extends "base.html" %}
{% block index %}
<p> hello </p>
{% endblock %}
I have done it several times before before but i am clueless as to why this is NOT working?
the urls and views are here.
Well everything is fine, the trouble that you are having is that
you are confused, just naming a block in base does not calls it.
Mark the difference between extends and include.
You have counfused extends to include.
Once in your views if you call say index.html it will be rendered properly.
The effect you want can be achieved by changing the base.html in your views to index.html.
Hope this helps. more can be read here: https://docs.djangoproject.com/en/dev/topics/templates/#template-inheritance
For more people who end up here (as myself), main thing to note is that when you use {% extends 'something.html' %}, you cannot use anything other than these template tags at the top-level.
You can obviously have html tags inside these tags (like block tags), but don't put ANYTHING outside the template tags.
Also helps if you change the path in extends, for example {% extends 'mysite/index.html' %}. And view function must render the file with extends, not the basic one.
In views.py, you have to call the template that extends the other template, not the other way around. In your example you should call nav.html.
try do this
{% extends 'appname/index.html' %}

Pageparts extending templates

Suppose I want to repeat some easy HTML structure on my site a lot of times.
For example, I want to display some parts of the pages "in green boxes".
The first mandatory step to achieve this goal would be to create a template file like this:
<!-- greenbox.html -->
<div style="background-color:#88ff88;"><br>
{% block content %}<br>
{% endblock %}<br>
</div>
Then every time I need this predefined template I have to create a separate template like the following:
<!-- pagepart_1.html -->
{% extends "greenbox.html" %}
{% block content %}
This time I want to add this dummy text in here
{% endblock %}
<!-- pagepart_2.html -->
{% extends "greenbox.html" %}
{% block content %}
The second time I want to add some other text
{% endblock %}
The actual page containing the green boxes will look like this:
<html><head>My Page</head>
<body>
<h1>Page Title</h1>
{% include "pagepart_1.html" %}
<br /><br />
{% include "pagepart_2.html" %}
</body></html>
This kind of approach does work, but I think it contains a little overhead.
Can I avoid the creation of separate templates for each instance (pagepart_1.html, pagepart_2.html, ...)?
So can I make my main page look something like this?
<html><head>My Page</head>
<body>
<h1>Page Title</h1>
{% unkowntag extend "greenbox.html" %}
{% block content %}
This time I want to add this dummy text in here
{% endblock %}
{% endunknowntag %}
<br /><br />
{% unkowntag extend "greenbox.html" %}
{% block content %}
The second time I want to add some other text
{% endblock %}
{% endunknowntag %}
</body></html>
Thanks a lot!
That's the only approach available it you want to allow for completely customizable content areas. However, if you can standardize the content, such that it will always display an unordered list, for example, you can do:
<!-- greenbox.html -->
<div style="background-color:#88ff88;"><br>
<ul>
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</div>
And then in your template:
<!-- mypage.html -->
{% with something as list %}
{% include 'greenbox.html' %}
{% endwith %}
You can do much more complex structures and even pass multiple variables (in Django 1.3+):
<!-- greenbox.html -->
<div style="background-color:#88ff88;"><br>
<h2>{{ title }}</h2>
<img style="float:{{ float }};" src="{{ image }}" alt="{{ alt_text }}">
<p>{{ description }}</p>
</div>
<!-- mypage.html -->
{% with title=obj.title image=obj.image.name alt_text=obj.title float="left" description=obj.description %}
{% include 'greenbox.html' %}
{% endwith %}
I would write a custom tag that emits the HTML and use it multiple times.