My for loop doesn't get the values - python

Here's what I have:
result = defaultdict(<type 'list'>,
{'USA': [{'username': 'user123', 'first-name': 'John', 'last-name': 'Doe'}],
'Europe': [{'username': 'myname654', 'first-name': 'Peter', 'last-name': 'Johnson'}]
})
Here's the output I want to get
<html>
<body>
<h1> USA </h1>
<p> user123, John Doe</p>
<h1> Europe </h1>
<p> myname654, Peter Johnson</p>
</body>
</html>
I've tried tons of different for loops, but none of them worked.
Here's what I have, but it doesn't work.
{% for item in result %}
<h1> {{ item }} </h1>
<p> {{ result.item.username }} </p>
{% endfor %}

Result is a dictionary. Iterating through a dictionary with for x in mydict just gives the keys, not the values. So you need to do {% for item, value in mydict.items %}.
Secondly, {{ result.item.username }} makes no sense at all. item is a the value of a key into the result dict, but you can't do that sort of indirect lookups in Django templates. However, luckily we have the value in the value variable.
Thirdly, as Kabie points out, each value is actually a single-element list. So you'll need to access the first item in that list, and then the username member of that.
Putting it all together:
{% for item, value in result.items %}
<h1> {{ item }} </h1>
<p> {{ value.0.username }} </p>
{% endfor %}

You are using print to get output in your for loop. This first converts the object to a string. Apparently the objects in this case is some sort of xml/html objects.
From inside the Django template, you don't print. You could try converting the objects to string via a str() call, but in general I have the feeling you are trying to make the templates do something that you shouldn't make templates to in the first place.
Try having a method on the model object that returns the string you want, and inserting that into the template instead.

I think the line:
<p> {{ result.item.username }} </p>
should be:
<p> {{ result.item.0.username }} </p>

Related

TemplateSyntaxError: 'for' statements should use the format 'for x in y' [duplicate]

With this code:
{% for o in [1,2,3] %}
<div class="{% cycle 'row1' 'row2' %}">
{% cycle 'row1' 'row2' %}
</div>
{% endfor %}
I get a TemplateSyntaxError:
Could not parse the remainder: '[1,2,3]' from '[1,2,3]'
Is there a way of building a list in a template?
We can use split method on str object :
page.html :
{% with '1 2 3' as list %}
{% for i in list.split %}
{{ i }}<br>
{% endfor %}
{% endwith %}
Results :
1
2
3
You can do it via cunning use of the make_list filter, but it's probably a bad idea:
{% for o in "123"|make_list %}
<div class="{% cycle 'row1' 'row2' %}">
{% cycle 'row1' 'row2' %}
</div>
{% endfor %}
p.s. You don't seem to be using o anywhere, so I'm not sure what you're trying to do.
I made this template tag to achieve this goal.
from django import template
register = template.Library()
# use #register.assignment_tag
# only when you're working with django version lower than 1.9
#register.simple_tag
def to_list(*args):
return args
to use it in template:
{% load your_template_tag_file %}
{% to_list 1 2 3 4 5 "yes" as my_list %}
{% for i in my_list %}
{{ i }}
{% endfor %}
Reference here:
Django simple tags
The other answers here look like the ticket (at least for what I wanted), so I'll provide an answer as to WHY you might want to do something like this (and perhaps there's a better answer for my case than what's been provided):
I came across this question looking for a way to build 3 very similar, but not identical buttons using Bootstrap. One button might look like
<div class="btn-group">
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">
Modality
<span class="caret"></span>
</a>
<ul class="dropdown-menu" id="Modality">
<li>Action</li>
</ul>
</div>
where the difference between buttons is limited to the text of the button (Modality, on its own line above) and the contents of the pertaining to the button, which we'll assume is filled dynamically by JS (referencing id="Modality").
If I need to make 10 of these, copy/pasting the HTML seems dumb and tedious, especially if I want to change anything about my button after the fact (like making all of them split-drop-downs) and it goes against DRY.
So, instead, in the template I could do something like
{% with 'Modality Otherbutton Thirdbutton' as list %}
{% for i in list.split %}
<!-- copy/paste above code with Modality replaced by {{ i }} -->
{% endfor %}
{% endwith %}
Now, granted, in this particular case the buttons add functionality to some related data grid, so the button names could be dynamically filled from django model-sourced data as well, but I'm not at that stage in my design right now, and you can see where this sort of functionality is desirable to maintain DRY.
The simplest is to do
{% for x in "123" %}
drodger is correct, you can't do that in the deliberately-crippled Django template lanuage. Either pass in the list as a context variable when you invoke the template or try a template tag like expr. Then you can say {% expr [1,2,3] as my_list %} and then use my_list in your for loop.
This maybe an inspiration. Use the buildin filter add.
{{ first|add:second }}
first is [1, 2, 3] and second is [4, 5, 6], then the output will be [1, 2, 3, 4, 5, 6].
This filter will first try to coerce both values to integers.
If this fails, it'll attempt to add the values together anyway.
This will work on some data types (strings, list, etc.) and fail on others.
If it fails, the result will be an empty string.
The official specification,https://docs.djangoproject.com/zh-hans/2.0/ref/templates/builtins/#built-in-filter-reference

Creating a list from CSV value in Jinja

In a flask template, I'd like to loop over my values which is a comma separated range of values. So in my template, I'd like to do something like:
{% for tag in list(myparent.my_tags) %}
{{tag}}
{% endfor %}
I can see list in the documents, but I don't see how to use it. http://jinja.pocoo.org/docs/dev/templates/
The value of my_tags is abc, def, ghi,... and the aim to loop over each group in turn.
Jinja2's split function should work.
{% for tag in myparent.my_tags.split(',') %}
{{ tag }}
{% endfor %}

Django template iterate over list inside request.GET

My today's problem is that I've to preserve some url arguments that comes to my view in the request.
Think about the following url:
http://localhost:8000/some-url/?myargument=hello&myargument=world&myargument=whatever
Noticed that every argument in my url has the same key ("myargument")? Keep that in mind
In Django 1.6 if I do {{ request.GET }} in the template I get something like:
<QueryDict: {u'myargument': [u'hello', u'world', u'whatever']}>
To preserve the arguments in the next submit I want to iterate over the request.GET dictionary by creating a hidden field inside the <form> with the key-value pairs, I can do it with this code:
{% for key, value in request.GET.items %}
<input type="hidden" name="{{ key }}" value="{{ value }}">
{% endfor %}
It works with single values, but not in my case because I've a list with the values of the key named "myargument".
Obviously the first thing I tried was to iterate over the value by doing {% for v in value %} when the value is a list, but this only prints out the last item in the "value" list, in this case "whatever".
Anyone had the same problem? How can I solve it? Thanks
in the view:
mydict = dict(request.GET._iterlists())
sent and iterate in the template:
<p>
{{ mydict }}
</p>
<p>
{% for k,v in mydict.iteritems %}
{{ k }}:{% for x in v %}{{ x }},{% endfor %} <br>
{% endfor %}
</p>

Jinja2 and Json

I have for example a JSON File
{
"Google":{
"Web":"www.web.de",
"Apps":{
"Drive": "DriveLink",
"Dropbox": "DropboxLink"
},
"Google Main":"http://mail.google.com",
"G+":"http://plus.google.com"
},
"Social":{
"Facebook":"http://www.facebook.de",
"G+":"https://plus.google.com",
"Xing":"http://www.xing.de",
"LinkedIn":"http://www.linkedin.com",
"Tumblr":"http://www.tumblr.com"
},
"Fun":{
"Reddit":"http://www.reddit.com"
}
}
As you can see I have under the section Google a Nested Section named Apps
With CherryPy I hand over this JSON Object as following with the name linksList:
#cherrypy.expose
def index(self):
linksFile = open('links.json', 'r')
linksList = json.load(linksFile)
template = jinjaEnv.get_template('index.html')
return template.render(linksList=linksList)
What I want is to render following:
Google
Web (as a link)
Google Main
G+
Apps
Drive
Dropbox
Social
Facebook
G+
Xing
and so on
What I don't understand is to do is to render this nested Objects like "Apps" recursively
The documentation reads:
It is possible to use loops recursively. This is useful if you are
dealing with recursive data such as sitemaps. To use loops recursively
you basically have to add the recursive modifier to the loop
definition and call the loop variable with the new iterable where you
want to recurse.
In your case this would be accomplished with the following:
<ul>
{% for key, value in linksList.items() recursive %}
<li>
{% if value is string %}
{{ key }}
{% else %}
{{ key }}
<ul>{{ loop(value.items()) }}</ul>
{% endif %}
</li>
{% endfor %}
</ul>
My 2 cents, just if someone comes here looking for rendering a JSON using Jinja, and complementing the response from #Ryon Sherman :)
Since JSON may have int values as well as strings, you can use if value is mapping (and flip the if-condition)
If your output must feel like a JSON you can use {{key|indent(width)}} + loop.depth
In my case, the template was for an email and key|indent() didn't work as expected so I ended up using an auxiliar {% for %} loop:
<div>
<code>{
{% for key, value in dic.items() recursive %}
{% if value is mapping %}
<p>
{% for it in range(loop.depth) %} {% endfor %}{{key}}: {
</p>
{{ loop(value.items()) }}
<p>
{% for it in range(loop.depth) %} {% endfor %}}
</p>
{% else %}
<p>
{% for it in range(loop.depth) %} {% endfor %}{{key}}: {{value}},
</p>
{% endif %}
{% endfor %}
}</code>
</div>

Django dictionary in templates: Grab key from another objects attribute

I have a dictionary called number_devices I'm passing to a template, the dictionary keys are the ids of a list of objects I'm also passing to the template (called implementations). I'm iterating over the list of objects and then trying to use the object.id to get a value out of the dict like so:
{% for implementation in implementations %}
{{ number_devices.implementation.id }}
{% endfor %}
Unfortunately number_devices.implementation is evaluated first, then the result.id is evaluated obviously returning and displaying nothing. I can't use parentheses like:
{{ number_devices.(implementation.id) }}
because I get a parse error. How do I get around this annoyance in Django templates?
Thanks for any help!
A workaround could be using the keys from number_devices and check in the for loop if it is equal to the key provided by number_devices.
{% for key in number_devices.keys %}
{% for implementation in implementations %}
{% ifequal key implementation.id %} you got it {% endifequal %}
{% endfor %}
{% endfor %}
Seems a bit ugly, but should work.

Categories