How can I check that variable is changed in jinja2 template? - python

I have the list of objects to show on web pages(HTML file).
And the type(graph, table etc.) of objects is different from the situation.
If there is a graph objects, I should load js and css files about a graph.
Because I do not want to load js, css files for graph when there is no graph object in the list,
I have implemented the following jinja2 template HTML file.
{% block body %}
{% set has_graph = 0 %}
{% for item in components %}
{% if item.form == 'graph' %}
{% set has_graph = 1 %}
{% endif %}
{% endfor %}
{% if has_graph == 1 %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
{% endif %}
{% endblock %}
I have found {% set has_graph = 1 %} worked, but the js file was not loaded.
I do not know why {% if has_graph == 1 %} does not work.

I found that the scope of set statement could not be beyond the loop in jinja2 document(http://jinja.pocoo.org/docs/2.9/templates/#id12).
Please keep in mind that it is not possible to set variables inside a block and have them show up outside of it. This also applies to loops. The only exception to that rule are if statements which do not introduce a scope. As a result the following template is not going to do what you might expect:
{% set iterated = false %}
{% for item in seq %}
{{ item }}
{% set iterated = true %}
{% endfor %}
{% if not iterated %} did not iterate {% endif %}
It is not possible with Jinja syntax to do this.

It is true that global variables are generally not within scope inside for loops in jinja, which is a surprise to many (users of Python, Java, etc).
However, the workaround is to declare a dictionary object in that outer scope, which is then available in the for-loop:
{% set foundItem = { 'found': False } %}
{% for item in seq %}
{%- if item.form == "graph" %}
{%- if foundItem.update({'found':True}) %} {%- endif %}
{%- endif %}
{% endfor %}
{% if not iterated %} did not iterate {% endif %}
{% if foundItem.flag %} pull in graph CSS/JS {% endif %}

Related

how to use Django template if condition inside Django Template?

{% if len(verifiedJobs) > 0 %}
{% for v in verifiedJobs %}
companyname:::{{v.companyname}}<br>
jobDescription::::{{v.jobDescription}}<br>
salary:::{{v.salary}}<br>
{% endfor %}
{% endif %}
this is my code and it is not working it is giving errors about my if condition.
Django templates don't understand the length function so that's why its giving you an error.
suppose the length of verifiedjob is 0 it will be considered as false and the if condition will not work and if its value is anything different than 0 it will work
{% if verifiedJobs %}
{% for v in verifiedJobs %}
companyname:::{{v.companyname}}<br>
jobDescription:::{{v.jobDescription}}<br>
salary:::{{v.salary}}<br>
{% endfor %}
{% endif %}

Access parent for loop scope in child template in Jinja2

parent.txt
{% for dict in list_of_dictionaries %}
{% block pick_dictionary_element %}
{% endblock %}
{% endfor %}
child_one.txt
{% extends "parent.txt" %}
{% block pick_dictionary_element %}
{{ dict.a }}
{% endblock %}
child_two.txt
{% extends "parent.txt" %}
{% block pick_dictionary_element %}
{{ dict.b }}
{% endblock %}
Then:
from jinja2 import Template, Environment, FileSystemLoader
e = Environment(loader=FileSystemLoader("./"))
e.get_template("child_one.txt").render(list_of_dictionaries=[{'a': 'a', 'b': 'b'}])
produces an empty output. How can I access the dict var from the parent for loop? I kind of imagined jinja just in-lining the pick_dictionary_element and the child having the for loop scope of its parent?
The key to what you are trying to do is to use the scoped keyword on your block:
{# parent.txt #}
{% for dict in list_of_dictionaries %}
{% block pick_dictionary_element scoped %}
{% endblock %}
{% endfor %}
Why was this hard to debug?
You made the mistake of using the name dict in the loop:
{% for dict in list_of_dictionaries %}
The side effect of this was that the child template did not readily complain, since the symbol dict exists in its context. If instead, you had done something like:
{# parent.txt #}
{% for a_dict in list_of_dictionaries %}
{% block pick_dictionary_element %}
{% endblock %}
{% endfor %}
{# child_one.txt #}
{% extends "parent.txt" %}
{% block pick_dictionary_element %}
{{ a_dict.a }}
{% endblock %}
You would have been told:
jinja2.exceptions.UndefinedError: 'a_dict' is undefined
Starting with Jinja 2.2, you can explicitly specify that variables are available in a block by setting the block to “scoped” by adding the scoped modifier to a block declaration
http://jinja.pocoo.org/docs/2.9/templates/#block-nesting-and-scope
{# parent.txt #}
{% for dict in list_of_dictionaries %}
{% block pick_dictionary_element scoped %}
{% endblock %}
{% endfor %}

include a template inside another but with extend

Here is what i want
tmpl1.jinja
{% for x in List %}
{% set User = List[x] %}
{% include 'tmpl2.jinja' %}
{% endfor %}
tmpl2.jinja
{% extends "tmpl3.jinja" %}
{% block link %}
<a>share</a>
{% endblock link %}
tmpl3.jinja
User.name
{% block link %}
{% endblock link %}
Basically i have a user block that exists across site with only the action(one or more link but with quiet a few html like image etc) changing. What can i do.
Thanks
For the template part everything looks absolutely ok and there should not be problem if what you do is what you showed.
Is Your list is dict() or actually list()?
Because your problem is here:
{% for x in List %}
{% set User = List[x] %}
This syntax will work only if List is dictionary.
In case of list you should write:
{% for x in List %}
{% set User = x %}

Setting and resetting value of variable in django template

I want to set and reset flag variable inside django template. Is there any way for doing that?
{% for software in softwares %}
//here want to asign default value to flag( flag = False)
{% for mysoftware in mysoftwares %}
{% if mysoftware.name == software.name %}
//here want to set value to True to flag( flag = True)
{{ software.name }}<br />
{% endif %}
{% endfor %}
//check flag here
{% if flag == False %}
Software not assigned.
{% endif %}
{% endfor %}
There isn't a way to do this to my knowledge. Perhaps precalculate a list of tuples in your view, and iterate over that instead - displaying the results. e.g.:
{% for software, assigned in software_list %}
{% if assigned %}
{{ software.name }}
{% else %}
Software not assigned
{% endif %}
{% endif %}
Then, in your view, just populate the software_list data with a simple python construct:
names = [mysoftware.name for mysoftware in mysoftwares]
software_list = [(software, software.name in names) for software in softwares]
And add this to your context.
It's often tempting to try to do too much in the template, and this isn't really what they're for. You gain far better readability if you keep your logic in python, where it belongs.

How can I use break and continue in Django templates?

I want to put break and continue in my code, but it doesn't work in Django template. How can I use continue and break using Django template for loop. Here is an example:
{% for i in i_range %}
{% for frequency in patient_meds.frequency %}
{% ifequal frequency i %}
<td class="nopad"><input type="checkbox" name="frequency-1" value="{{ i }}" checked/> {{ i }} AM</td>
{{ forloop.parentloop|continue }} ////// It doesn't work
{ continue } ////// It also doesn't work
{% endifequal %}
{% endfor%}
<td class="nopad"><input type="checkbox" name="frequency-1" value="{{ i }}"/> {{ i }} AM</td>
{% endfor %}
Django doesn't support it naturally.
You can implement forloop|continue and forloop|break with custom filters.
http://djangosnippets.org/snippets/2093/
For-loops in Django templates are different from plain Python for-loops, so continue and break will not work in them. See for yourself in the Django docs, there are no break or continue template tags. Given the overall position of Keep-It-Simple-Stupid in Django template syntax, you will probably have to find another way to accomplish what you need.
For most of cases there is no need for custom templatetags, it's easy:
continue:
{% for each in iterable %}
{% if conditions_for_continue %}
<!-- continue -->
{% else %}
... code ..
{% endif %}
{% endfor %}
break use the same idea, but with the wider scope:
{% set stop_loop="" %}
{% for each in iterable %}
{% if stop_loop %}{% else %}
... code ..
under some condition {% set stop_loop="true" %}
... code ..
{% endif %}
{% endfor %}
if you accept iterating more than needed.
If you want a continue/break after certain conditions, I use the following Simple Tag as follows with "Vanilla" Django 3.2.5:
#register.simple_tag
def define(val=None):
return val
Then you can use it as any variable in the template
{% define True as continue %}
{% for u in queryset %}
{% if continue %}
{% if u.status.description == 'Passed' %}
<td>Passed</td>
{% define False as continue %}
{% endif %}
{% endif %}
{% endfor %}
Extremely useful for any type of variable you want to re-use on template without using with statements.

Categories

Resources