Django Template overriding - django

I was wondering, when using templates in django, I'm able to extend other base templates and override some of the blocks in the base template. so my question is when I override, would the code in the overridden block still get rendered then overridden, or would it never be run and only the new block is rendered?
Example:
base.html
{% block menu %}
{% for option in menu %}
...Create the menu entries
{% endfor %}
{% endblock menu %}
extender.html
{% extends base.html %}
{% block menu %}
... some other tags
{% endblock menu %}
In this case does the original for loop in the base.html run if it gets overridden?

As far as I know the block will be overwritten unless you want to preserve its code in your extended template.
If you want to preserve the original block you can use {{ block.super }}
base.html
[...]
<body>
{% block header %}
base header content
{% endblock %}
[...]
</body>
extended.html
{% extends "base.html" %}
{% block header %}
{{ block.super }}
new content added
{% endblock %}
[...]
G.

Related

Nesting Django block with {% include %}

I am trying to nest blocks with Django 3. I have sections of html that are sometimes reused on a page. I don't think I would have to resort to duplicating templates, but I can't get it to work;
I have this template
{% extends 'base.html' %}
{% include 'site_part.html' %}
{% block content %}
Some Content
<br>
And here I insert the child content
{% block part_of_site %}
{% endblock %}
{% endblock %}
And the site_part_html is like this;
{% block part_of_site %}
Okay, i am loaded!
{% endblock %}
In the base.html I have only this:
{% block content %}
{% endblock %}
I'd expect it to render the "Okay, i am loaded!" string in the resulting page, in the content block. However, it remains empty. I've looked, but most examples are far more advanced then what I need and I can't get those to work either.
If I remove the extends statement at that start and the block content lines, it does load the included html.
Basically, I have a site part that sometimes is need, and I'd like to included that based on some templating. Otherwise, I'd have duplicate that code for each of the pages that it occurs on.
You may call the content from the block 'part_of_site' in any child template using {{ block.super }} like this:
{% extends 'site_part.html' %}
{% block content %}
Some Content
<br>
{% block part_of_site %}
{{ block.super }}
{% endblock %}
{% endblock %}
You should use {% extends 'base.html' %} in the 'site_part.html' template. All children of 'site_part.html' will also be a descendant of base.html
{% extends 'base.html' %}
{% block part_of_site %}
Okay, i am loaded!
{% endblock %}
If you want to use {% include %} instead, change your code like this:
{% extends 'base.html' %}
{% block content %}
Some Content
<br>
{% include 'site_part.html' %}
{% endblock %}
You need to move your {% include 'site_part.html' %} into the {% block content %} block.
content.html
{% extends 'base.html' %}
{% block content %}
Some Content
<br>
And here I insert the child content
{% include 'site_part.html' %}
{% block part_of_site %}
{% endblock %}
{% endblock %}
Then, in your view you need to return your content template. I named it content.html here.
def your_view(request):
return render(request, "content.html")
You can put the include anywhere inside the content block, it doesn't have to be right before the part_of_site block.

Django, override template block conditionally

{% extends "Flow/base.html" %}
{% if no_tracking %}
{% block head %}
{% include "Flow/common/tracking/disabled.html" %}
{% endblock %}
{% endif %}
The snippet of code aboves overrides the head block in base.html, even though no_tracking is False. How can I make this behavior conditional?
I thought of this:
{% block head %}
{% if no_tracking %}
{% include "Flow/common/tracking/disabled.html" %}
{% else %}
<!-- How can I get "head" of base.html here? -->
{% endif %}
{% endblock %}
But this would also override the head of base.html.
head of base.html is not empty, it contains scripts that must be on the page when no_tracking is False.
I could override them in base.html, but base.html has no concept of no_tracking since that is a context variable passed to the view being rendered and not the one it extends.
How can I solve this?
You can make use of {{ block.super }} [Django-doc] to obtain the content that is rendered by the "parent" block:
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 (…), since it was already escaped, if necessary, in the parent template.
So here we can use it to add some "extra content" to the block:
{% block head %}
{% if no_tracking %}
{% include "Flow/common/tracking/disabled.html" %}
{% endif %}
{{ block.super }}
{% endblock %}

Extending Django Admin templates

I try to modify django admin templates
I created custom template with the name corresponding to template, that I want to override.
I try the following
{% extends "admin/change_form.html" %}
<h1>HELLO</h1>
If I reload the page I dont see h1 tag.
If I try
{% extends "admin/change_form.html" %}
{% block field_sets %}
<h1>HELLO</h1>
{% endblock %}
I seen only h1 tag and dont see model's editing fields.
What have I do to see form and h1 tag in same time ?
This should work:
{% extends "admin/change_form.html" %}
{% block field_sets %}
{{ block.super }}
<h1>HELLO</h1>
{% endblock %}
You must call the block from the source change_form.html template. Do that with {{ block.super }} as shown above. You can, of course, reverse the order between super and h1 according to your needs.

django template extend - all but one template

I have a piece of html that I want present in all pages, except one. If not for this page, I would have put it in the base.html and extended.
Is there a way other than putting the code individually in all the required pages?
From template-inheritance docs,
The template engine will notice the {% block %} tags in base.html and replace those blocks with the contents of the child template.
BUT
If the child template didn’t define the block, the value from the
parent template is used instead. Content within a {% block %} tag in a
parent template is always used as a fallback.
So in that case you can use {% block %} tag in the base.html.
{% block content %}
<!-- Your content here-->
{% endblock %}
You don't have to define that block in every template as the parent {% block %} is used as an fallback.
{% extends 'base.html' %}
So in your exceptional case just define that {% block %} tag with no data or something else.
{% extends 'base.html' %}
{% block content %}
<!-- Nothing goes here -->
{% endblock content %}
You can put it into a block that gets overridden with nothing in order to have it ignored. For example:
base.html
{% block content %}
<div>
This should show on all pages except for this one
</div>
{% endblock content %}
included-page.html (The div will be included on this page)
{% extends 'base.html' %}
ignored-page.html (The div will be ignored on this page)
{% extends 'base.html' %}
{% block content %}
{% endblock content %}

How to extend a base.html using two different files?

I'm writing an application in which user can choose one of several tools for data analysis and open it in a panel on main page. Is it possible to use django "extends" and have each tool defined in different file?
The minimal example of what im strugling with would be like this:
base.html
<div>
{% block left_panel %}
left block
{% endblock content%}
</div>
<div>
{% block right_panel %}
right block
{% endblock %}
</div>
and sample left_panel and right_panel tools:
left1.html
{% extends "base.html" %}
{% block left_panel %}
<p>TEST left 1</p>
{% endblock %}
right1.html
{% extends "base.html" %}
{% block right_panel %}
<p>TEST right 1</p>
{% endblock %}
Is there a way to render the base.html with both blocks overwriten?
I believe that the best way to implement your requirement is to create a new template that extends base.html and includes left1.html and right1.html. Something like this:
{% extends "base.html" %}
{% block left_panel %}
{% include "left1.html" %}
{% endblock content%}
{% block right_panel %}
{% include "right1.html" %}
{% endblock %}
Update based on OP's comment: Actually you just need one configurable template, not 100. Let's say that based on the tools the user selects, your view passes the left_tool and right_tool context variables to your template. Now, you can easily do something like this:
{% block left_panel %}
{% if left_tool == "tool1" %}
{% include "left1.html" %}
{% elif left_tool == "tool2" %}}
{% include "left2.html" %}
etc ...
{% else %}
{% include "left10.html" %}
{% endif %}
{% endblock content%}
You'll do the same with the right panel. Of course the above is a little naive and definitely not DRY -- instead you could for instance generate the name of the template to be included in the view and pass it directly to the template, or use a custom node etc.