I'm doing code generation in Jinja2 and I frequently want to iterate through two lists together (i.e. variables names and types), is there a simple way to do this or do I need to just pass a pre-zipped list? I was unable to find such a function in the docs or googling.
Modify the jinja2.Environment global namespace itself if you see fit.
import jinja2
env = jinja2.Environment()
env.globals.update(zip=zip)
# use env to load template(s)
This may be helpful in separating view (template) logic from application logic, but it enables the reverse as well. #separationofconcerns
Since you didn't mention if you are using Flask or not I figured I'd add my findings.
To be used by a render_template() create the 'zip' filter using the zip() function in the Jinja2 environment used by Flask.
app = Flask(__name__)
...
app.jinja_env.filters['zip'] = zip
To use this within a template do it like this:
{% for value1, value2 in iterable1|zip(iterable2) %}
{{ value1 }} is paired with {{ value2 }}
{% endfor %}
Keep in mind that strings are iterable Jinja2 so if you try to zip to strings you'll get some crazy stuff. To make sure what you want to zip is iterable and not a string do this:
{% if iterable1 is iterable and iterable1 is not string
and iterable2 is iterable and iterable2 is not string %}
{% for value1, value2 in iterable1|zip(iterable2) %}
{{ value1 }} is paired with {{ value2 }}
{% endfor %}
{% else %}
{{ iterable1 }} is paired with {{ iterable2 }}
{% endif %}
For Flask, you can pass the zip in the render_template()
return render_template("home.html", zip=zip)
I don't think templating languages allow doing zip of two containers over for loop. Here is a similar question for django and jinja templating is very close to django's.
You would have prebuild zipped container and pass to your template.
>> for i,j in zip(range(10),range(20,30)):
... print i,j
...
Is equivalent to
>>> [(i,j) for i,j in zip(range(10),range(20,30))]
Related
I'm doing code generation in Jinja2 and I frequently want to iterate through two lists together (i.e. variables names and types), is there a simple way to do this or do I need to just pass a pre-zipped list? I was unable to find such a function in the docs or googling.
Modify the jinja2.Environment global namespace itself if you see fit.
import jinja2
env = jinja2.Environment()
env.globals.update(zip=zip)
# use env to load template(s)
This may be helpful in separating view (template) logic from application logic, but it enables the reverse as well. #separationofconcerns
Since you didn't mention if you are using Flask or not I figured I'd add my findings.
To be used by a render_template() create the 'zip' filter using the zip() function in the Jinja2 environment used by Flask.
app = Flask(__name__)
...
app.jinja_env.filters['zip'] = zip
To use this within a template do it like this:
{% for value1, value2 in iterable1|zip(iterable2) %}
{{ value1 }} is paired with {{ value2 }}
{% endfor %}
Keep in mind that strings are iterable Jinja2 so if you try to zip to strings you'll get some crazy stuff. To make sure what you want to zip is iterable and not a string do this:
{% if iterable1 is iterable and iterable1 is not string
and iterable2 is iterable and iterable2 is not string %}
{% for value1, value2 in iterable1|zip(iterable2) %}
{{ value1 }} is paired with {{ value2 }}
{% endfor %}
{% else %}
{{ iterable1 }} is paired with {{ iterable2 }}
{% endif %}
For Flask, you can pass the zip in the render_template()
return render_template("home.html", zip=zip)
I don't think templating languages allow doing zip of two containers over for loop. Here is a similar question for django and jinja templating is very close to django's.
You would have prebuild zipped container and pass to your template.
>> for i,j in zip(range(10),range(20,30)):
... print i,j
...
Is equivalent to
>>> [(i,j) for i,j in zip(range(10),range(20,30))]
I want to make a counter
this simple code not working...
{% set count = 1 %}
{% for i in [1,2,3,4,5] %}
{% set count = count + 1 %}
{% endfor %}
<h2>found {{count}}<h2>
the result is 1
i see you can use this How to increment a variable on a for loop in jinja template? but this is not work for me
If you're using Flask and Jinja2, you can use the built in filter length.
{% set my_list = [1,2,3,4,5] %}
{% for i in my_list %}
...
{% endfor %}
<h2>found {{my_list|length}}<h2>
If that doesn't do exactly what you want, you can also expose custom filter or functions from your Flask app when it is initialized by using add_template_filter() or add_template_global()
There are situations where it's more appropriate to do the counting prior to template rendering, passing the count in to the template. You might be looking at one of those. The Jinja2 template "language" is not a full, turing-complete programming language.
I have a dictionary passed (as part of another object) to the django template language.
The object, called 'poll' has attributes self.text and self.votes, where the former is a string, and the latter is a dict.
The dict, looks like this:
{'a1': 45.92422502870264, 'a2': 53.50172215843857}
I am trying to list each label, with its accompanying number, using the following:
{% for l, x in poll.votes %}
<p>{{ l }} {{ x }}</p>
{% endfor %}
Django responds with
Exception Type: ValueError
Exception Value: Need 2 values to unpack in for loop; got 3.
I tried .iteritems - The docs explain that .iteritems is not the correct way to do this, but they don't explain what the correct way is.
You just iterate the same way you would in python, but in Djangos templating language (DTL) syntax
{% for key, value in dictionary.items %}
Your poll.votes is a dict but you're not iterating the items but the keys in your code.
You can find an overview of jinja here. Its worth noting that jinja isn't what django uses but its handy for a condensed reference since many things are the same (jinja is based upon DTL) instead of digging through djangos docs.
For Djangos tempaltes heres the documentation reference
you too can do this:
{% for variable in poll %}
{{ variable.name }} - {{ variable.votes }}
{% endfor %}
I have a list created in Django view:
list = [ elem1, elem2, ..., elemN ]
The list is variable length: it can contain 0-6 elements. I want to iterate over the list in the template, but I would like the loop to run always 6 times, yielding None or empty string for non-existing elements.
I tried something like this:
{% for i in "0123456" %}
{{ list.i }}
{% endfor %}
but this obviously doesn't work. I know I could do this in the view, but I would like to have this in the template. Is is possible?
You can add an if statement checking if it is your 6th time through the loop.
{% for item in someList %}
{% if forloop.counter <= 6 %}
{{ item }}
{% endif %}
{% endfor %}
http://docs.djangoproject.com/en/1.3/ref/templates/builtins/#for in the docs.
Of course, if your list is very long then this is not optimal. I would also suggest processing the list in views.py and then passing it to the template. Logic should stay in the views if possible.
This gives you control over the number of loops done. To completely solve your problem you will need some addtional logic but see my note above regarding this.
Check this snippet: Template range filter
This may be simple, but I looked around and couldn't find an answer. What's the best way to reference a single item in a list from a Django template?
In other words, how do I do the equivalent of {{ data[0] }} within the template language?
It looks like {{ data.0 }}. See Variables and lookups.
A better way: custom template filter: https://docs.djangoproject.com/en/dev/howto/custom-template-tags/
such as get my_list[x] in templates:
in template
{% load index %}
{{ my_list|index:x }}
templatetags/index.py
from django import template
register = template.Library()
#register.filter
def index(indexable, i):
return indexable[i]
if my_list = [['a','b','c'], ['d','e','f']], you can use {{ my_list|index:x|index:y }} in template to get my_list[x][y]
It works fine with "for"
{{ my_list|index:forloop.counter0 }}
Tested and works well ^_^
{{ data.0 }} should work.
Let's say you wrote data.obj django tries data.obj and data.obj(). If they don't work it tries data["obj"]. In your case data[0] can be written as {{ data.0 }}. But I recommend you to pull data[0] in the view and send it as separate variable.
#jennifer06262016, you can definitely add another filter to return the objects inside a django Queryset.
#register.filter
def get_item(Queryset):
return Queryset.your_item_key
In that case, you would type something like this {{ Queryset|index:x|get_item }} into your template to access some dictionary object. It works for me.