Django: with tag outside blocks - django

It seems like the 'with' tag is not working if it is declared outside of a block as this:
{% extends 'base.html' %}
{% with my_var=1 %}
{% block test1 %}
{{my_var}}
{% endblock %}
{% block test2 %}
{{my_var}}
{% endblock %}
{% endwith %}
The template above simply displays nothing since my_var is NOT passed inside those blocks.
How can I overcome this?

I came to Django from using Tornado with Jinja2 and I was being driven insane by the inability to set variables that (a) could be defined in the template (not view) and (b) would be available in the base template that this derives from. Looking at a little four-line piece of code from django-libs, I was able to rig up something like this that worked well. Here is an example of a title string that should appear in various blocks.
settings.py -- add to TEMPLATES (Django 1.10+)
TEMPLATES = {
...
builtins = ['mysite...wherever...templatetags',]
}
mysite.whereever.templatetags.py
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def setvar(context, key, value):
context.dicts[0][key] = value
return ''
base.html
{% block settings %}
{% comment %}
Put this at the TOP of the template before
any blocks that use variables.
{% endcomment %}
{% endblock settings %}
<html>
<head><title>{{title}}</title></head>
<body><h1>My Site: {{title}}</h1>
{% block body %}
{% endblock body %}
</body></html>
menu.html -- a template that does not set 'title' in views:
{% extends "base.html" %}
{% block settings %}
{{ block.super }} {% comment %}optional{% endcomment %}
{% setvar 'title' 'Menu' %}
{% endblock %}
{% block body %}
<ul><li>Fish</li><li>Steak</li></ul>
{% endblock %}
Now the title will appear in two places in the HTML even though it is defined in the derived template but appears in the top template.

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 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.

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.

extend other app to my template working

I want to extend an other template to my blog.html, no matter have i try to extend this, it doesn`t work .
blog/index.html
{% block nav %}
<ul id="nav">
<li>{% block nav-blog %}Blog{% endblock %}</li>
<li>{% block nav-photo %}Photo{% endblock %}</li>
</ul>
{% endblock %}
<div class="news">
{% block polls %}
{% extends 'polls/index.html' %}
{% endblock %}
<div>
polls/index.html
{% if latest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li>{{ poll.question }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
Usually extends has to be stuck at the top of the template and not somewhere in the template.
In the template you use the tags that you have set up in the base templates.
You need to make sure you're doing two things here:
Declare a "nav" block in your index.html. This will let django know the part of your index html you wish to have overwritten when a template extends it. Anything you put inside the "nav" block in index html will be considered default content.
You need to use the "extends" template tag at the beginning of your blog.html so django knows the template you'd like to extend.
Like this:
index.html
{% block nav %}
<div>
Some default html here..
</div>
{% endblock %}
And then blog.html
{% extends index.html %}
{% block nav %}
<div>
This is what will render
</div>
{% endblock %}
Also, you're going to want to test index.html before trying to extend it to verify that django is finding that template. If it isn't then you need to add the directory that it is found in to the TEMPLATE_DIRS array in your settings.py file.