What template system could I use to generate text fragments for all combination of input arrays? - jinja2

I have a 'template' that I wish to use to create potentially millions of text fragment, lets say this
Fragment {{loop1}}_{{loop2}}
Now, I define that the loop1 is from 1 to 3 and loop2 is from A to C. I want a template system to generate:
Fragment 1_A
Fragment 1_B
Fragment 1_C
Fragment 2_A
Fragment 2_B
...
Fragment 3_C
What should I use in this case?

with jinja2 you could play with something like this:
{% set loop1 = [1,2,3] %}
{% set loop2 = [A,B,C] %}
{% for i1 in loop1 %}
{% for i2 in loop2 %}
Fragment {{i1}}_{{i2}}
{% endfor %}
{% endfor %}

Related

How to increment two variables on a for-loop in jinja template?

I am developing a web using flask. I have two class objects from models.py. I need to loop over both of them at the same time in my HTML file using Jinja2.
For example:
I want to have the following code in jinja2 format:
for i,j in zip(items, team):
a= i+j
Want to convert it to jinja2 format:
{% for i,j in zip(items, teams) %}
{% a=i+j %}
{% endfor%}
What is the problem with this jinja2 code?
Jinja doesn't actually have a zip global function. So you need to make it available by doing:
app.jinja_env.globals.update(zip=zip)
Additionally, assignments require using the set keyword, e.g. {% set a = i + j %}
{% for i, j in items %}
{% set a = i + j %}
{% endfor %}
See also: "zip(list1, list2) in Jinja2?"
Thank you , it was very helpful. I just did this and worked:
in init.py file I add this:
app.jinja_env.filters['zip'] = zip
in the index.html:
{% for i, j in items | zip(teams) %}
{% set a = i + j %}
{% endfor %}

Accessing values of multiple lists using an index in Django template tags [duplicate]

I have two list objects of the same length with complementary data i want to render is there a way to render both at the same time ie.
{% for i,j in table, total %}
{{ i }}
{{ j }}
{% endfor %}
or something similar?
If both lists are of the same length, you can return zipped_data = zip(table, total) as template context in your view, which produces a list of 2-valued tuples.
Example:
>>> lst1 = ['a', 'b', 'c']
>>> lst2 = [1, 2, 3]
>>> zip(lst1, lst2)
[('a', 1), ('b', 2), ('c', 3)]
In your template, you can then write:
{% for i, j in zipped_data %}
{{ i }}, {{ j }}
{% endfor %}
Also, take a look at Django's documentation about the for template tag here. It mentions all possibilities that you have for using it including nice examples.
For any recent visitors to this question, forloop.parentloop can mimic the zipping of two lists together:
{% for a in list_a %}{% for b in list_b %}
{% if forloop.counter == forloop.parentloop.counter %}
{{a}} {{b}}
{% endif %}
{% endfor %}{% endfor %}
Use python's zip function and zip the 2 lists together.
In your view:
zip(table, list)
In your template, you can iterate this like a simple list, and use the .0 and .1 properties to access the data from table and list, respectively.
If it's just the variables i and j that you're looking at then this should work -
return render_to_response('results.html',
{'data': zip(table, list)})
{% for i, j in data %}
<tr>
<td> {{ i }}: </td> <td> {{ j }} </td>
</tr>
{% endfor %}
(credit to everyone else who answered this question)
Rather than using a dictionary (which does not guarantee any kind of sorting), use the python zip function on the two lists and pass it to the template.
You'll have to do this in the view - use the builtin zip function to make a list of tuples, then iterate over it in the template.
Template logic is purposely simple, anything even slightly complex should be done in the view.

How to get datas with multiple variables in path with jekyll and liquid

At its most basic level I need to append a partial object path onto an existing object path. In this particular instance I can't use plugins.
Say you have an object path:
{{ site.data.grants.2015.Return.ReturnHeader.ReturnTypeCd }}
Which, of course, can also be referenced as follows:
{% assign var = "ReturnTypeCd" %}
{{ site.data.grants.2015.Return.ReturnHeader[var] }}
How would I go about adding additional levels of nesting to the variable?
{% assign xTest = "Return.ReturnHeader.ReturnTypeCd" %}
{{ site.data.grants.2015[xTest] }}
//does not work
I've played around with both dot and bracket notations and using append as well as capture, but can't seem to find a solution that works.
This works :
Data file is _data/grants.yml
"2015":
Return:
ReturnHeader:
ReturnTypeCd: "Et hop !"
Getting deep target with a "dotted" string :
{% assign dataPath = site.data.grants.2015 %}
{% assign target = "Return.ReturnHeader.ReturnTypeCd" %}
{% comment %} ++++ Transform target string to an array {% endcomment %}
{% assign labels = target | split:"." %}
{% comment %} ++++
Looping in labels array and reassigning dataPath on each loop.
This goes deeper and deeper in the data tree
++++ {% endcomment %}
{% for label in labels %}
<h2>Label : {{ label }}</h2>
{% assign dataPath = dataPath[label] %}
<p>dataPath : {{ dataPath }}</p>
{% endfor %}

Does Liquid have a "does not contain" or "not in array" operator?

When calling items from an array in a Liquid template, how do you call does not contain or not in array?
unless to the rescue !
Create an [A, B, C] array.
{% assign input = "A,B,C" | split:"," %}
unless print only if constrain is not met.
This prints nothing:
{% unless input contains 'A' %}No A{% endunless %}
This prints "No Z":
{% unless input contains 'Z' %}No Z{% endunless %}
you could do something like this:
{% if collection.tags contains 'tag' %}
{% else %}
do stuff!
{% endif %}

Jinja2 for loop behaving similarly to with

I'd like to iterate over a set of objects and find the maximum of one particular attribute, however jinja2 ignores any action within an iterator on a variable declared outside of the iterator. For example:
{% set maximum = 1 %}
{% for datum in data %}
{% if datum.frequency > 1 %}
{% set maximum = datum.frequency %}
{% endif %}
{% endfor %}
{# maximum == 1 #}
datum.frequency is definitely greater than 1 for some datum in data.
EDIT (solution)
This is similar to this post, but there's a bit more to it. The following works and is very ugly.
{% set maximum = [1] %}
{% for datum in data %}
{% if datum.freq > maximum[-1] %}
{% if maximum.append( datum.freq ) %}{% endif %}
{% endif %}
{% endfor %}
{% set maximum = maximum[-1] %}
Have you considered writing a custom filter to return the highest value of a particular attribute within your collection? I prefer to minimize the amount of logic I use in Jinja2 templates as part of maintaining a 'separation of concerns'.
Here is a link to a very good example of how one can be written in python:
Custom jinja2 filter for iterator
Once you have your filter returning the value you need access it by using '|' like so:
{% set maximum = datum|filtername %}