Django, override template block conditionally - django

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

Related

request.user not available in Streamblocks subtemplate

In my main template I can call:
{% load static wagtailuserbar wagtailcore_tags %}
{% load navigation_tags %}
{% if request.user.is_authenticated %}
You're logged in
{% endif %}
but if I call this in my StreamBlock sub-template, it doesn't work.
{% load wagtailcore_tags wagtailimages_tags %}
{% if request.user.is_authenticated %}
<div class="container">
...
</div>
{% endif %}
Any ideas?
When outputting the StreamField onto the page, be sure to use the include_block tag rather than just outputting the value within a {{ ... }} tag. This ensures that any variables defined on the outer template, including request, are passed on to the sub-template. If you use {{ ... }}, the sub-template will still be rendered, but the only available variables are the ones supplied by the block itself.
{% include_block %} can be used on an individual block, or the stream as a whole:
{% load wagtailcore_tags %}
{% include_block page.body %}
or
{% for block in page.body %}
{% include_block block %}
{% endfor %}
You'll also need to do this within any sub-templates that render sub-sub-templates (for example, if you have a nested StreamBlock within the StreamField, the template for that StreamBlock needs to use include_block too).

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 Template overriding

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.

Is there a way to pass a variable to an 'extended' template in Django?

I want to add some flexibility to my layout template, but I can't find any way to do so.
I'm looking for a way to extend my layout template with variable, i.e. to pass a variable up in the template tree, not down.
# views.py
def my_view_func(request):
return render(request, "child.html")
# child.html
{% extends 'layout.html' with show_sidebar=True sidebar_width_class="width_4" %}
<div>Templates stuff here</div>
# layout.html
{% if show_sidebar %}
<div class="{{ sidebar_width_class }}">
{% block sidebar %}{% endblock %}
</div>
{% endif %}
I have to maintain four templates with a difference in a few lines of code. For example, I have two templates that differ from each other by a sidebar width class. Am I doing something wrong?
I suspect that block is what you are looking for in the first place.
Form your block inside the base template like this:
{% block sidebar_wrapper %}
{% if sidebar %}
<div class="width{{sidebar_width}}">
{% block sidebar %}{% endblock %}
</div>
{% endif %}
{% endblock sidebar_wrapper%}
And on your child template:
{% extends 'layout.html' %}
{% block sidebar_wrapper %}
{% with sidebar=True sidebar_width=4 %}
{{ block.super }}
{% endwith%}
{% endblock sidebar_wrapper%}
What you need is an include template tag. You can include a template in another template and render that with specific context.
{% include 'layout.html' with sidebar=True sidebar_width=4 %}
Check docs here: https://docs.djangoproject.com/en/2.2/ref/templates/builtins/#include
You can achieve this with some technique. I'll show the code then explain below.
# layout.html
{% block content %}
{% if show_sidebar %}
<div class="{{ sidebar_width_class }}">
{% block sidebar %}{% endblock %}
</div>
{% endif %}
{% endblock %}
# child.html
{% extends 'layout.html' %}
{% block content %}
{% with show_sidebar=True sidebar_width_class="width_4" %}
{{ block.super }}
{% endwith %}
{% endblock %}
In layout.html, wrap everything inside {% block content %}
In child.html, {{ block.super }} is like python's super(), which renders everything in the parent template's block. So if you wrap it inside {% with %} tag, all variables that you declare there will be available inside the parent template as well.

Django - block tags in included templates don't work - Why?

This question is kinda similar to this one, except for one small change -
I have block tags in the parent.html, and some are filled in the calling template, some others in the included template. The included ones don't work. Eg:
#parent.html
<head>{% block head %}Parent head {% endblock %} </head>
<body> {% block body %} Parent body {% endblock %}
</body>
#include.html
{%block body %} Child body {% endblock %}
#child.html
{% extends 'parent.html' %}
{% block head %}
Child head
{% endblock %}
{% include 'include.html' %}
But this gives output :
Child head
Parent body
intsead of the desired :
Child head
Child body
Any workarounds?
This :
{% include 'include.html' %}
is not included in any block, and will not be rendered, as you see in response.
Modify your child.html in that way:
#child.html
{% extends 'parent.html' %}
{% block head %}
Child head
{% endblock %}
{% block body %}
{% include 'include.html' %}
{% endblock %}
if you want to define some html in both child.html and in include.html, then you should have:
#child.html
{% extends 'parent.html' %}
....
{% block body %}
{% include 'include.html' %}
some child html...
{% endblock %}
and in include.html:
{% block body %}
{{ block.super }}
some include html...
{% endblock %}
This will render:
some child html
some include html