Iterating through a python dictionary in flask jinja - python

I have a dictionary which has all the country codes and the corresponding country names, a sample of it looks like this:
{'AF': 'Afghanistan'}
{'AL': 'Albania'}
{'DZ': 'Algeria'}
{'AD': 'Andorra'}
{'AO': 'Angola'}
When i followed this stack overflow question: How to iterate through a list of dictionaries in Jinja template? to try and iterate through the countries I had an issue as it's not adding any elements.
This is my code:
{% extends "base.html" %} {% block title %}Test{% endblock %}
{% block content %}
<div class="container pt-5">
<h1 align="center">TEST PAGE</h1>
</div>
{% for dict_item in countries %}
{% for key,value in dict_item.items %}
<h1>Key: {{ key }}</h1>
<h2>Value: {{ value }}</h2>
{% endfor %}
{% endfor %}
{% endblock %}
It's not adding any headings and when i tried dict_items.items() (with brackets after items), I got an error of: jinja2.exceptions.UndefinedError: 'str object' has no attribute 'items'
I'm not too sure what's going wrong. Any help would be much appreciated.
(Just incase it's useful, this is my views.py:)
#views.route("/test", methods=["GET"])
#login_required
def test():
countries = Country.query.all()
for country in countries:
countriess = {}
countriess[country.country_code] = country.country_name
print(countriess)
return render_template("TEST.html", user=current_user, countries=countriess)

Try changing views.py to:
#views.route("/test", methods=["GET"])
#login_required
def test():
countries = Country.query.all()
countriess = []
for country in countries:
countriess.append({country.country_code: country.country_name})
return render_template("TEST.html", user=current_user, countries=countriess)
This code will create a list of dictionaries countries, there is not need to change the templating code.

in views.py, you set countries=countriess for template rendering. countriess is re-initialised in the for loop in the test function (countriess = {}), so the countriess passed along to the template is actually a {country_code: country_name} pair for the last country from the countries list.
Going back to the actual error though: when you iterate over countries dictionary within the template ({% for dict_item in countries %}), you actually iterate over keys of countries, which, as I said before, is countriess from the views.py, so basically you just retrieve the country_code of the last country from countries. So the dict_item is actually a string (country code), hence you get the error for {% for key,value in dict_item.items %}, thinking that it is actually a dictionary and not a string.
TL;DR I think that you meant to do countries=countries rather than countries=countriess in views.py. Then the rest of the code would make sense. (I assume the for loop with countriess was just for debugging?)

Related

How to loop through dictionary in jinja template

I have a dictionary that looks something like this:
{
'Team Starwars': {'Luke Skywalker': {('Jedi', 100)}}
'Team helloworld': {'Beginner': {('newbie', 100)}}
}
And now I want to iterate through the dictionary with jinja in a template.
I have tried somethings but can't iterate through it correctly.
The code I have now looks something like this:
{% for team_name in team_resource %}
{% for team, name in team_resource.items %}
{% for role, allocation in subrole %}
{% if forloop.counter0 != 0 %}<br>{% endif %}
{{role}} {{allocation}} %
{% endfor %}
{% endfor %}
team_resource is the dictionary that I pass to the template, and in the first loop I can access the first part of the dictionary and print out like Team Starwars and Team helloworld', but can't access the rest of the dict.
How should I do this?
You should use team_resource.items() instead of team_resource.items to access dict items.
What you refer to as 'the rest of the dict' is actually the value of the key you managed to retrieve successfully.
Without testing, I believe the variable name is the one that holds the {'Luke Skywalker': {('Jedi', 100)} part of the dictionary in your example.

Jinja List Issue

I am getting a weird problem in Jinja, I have a list endpoints, which contains dictionary for every endpoint. In each dictionary, there is a key tags which is a list. Every item in tags is itself a dictionary where the key value gives the label of a tag. endpoint may have similar tags.
A sample abstract representation of an endpoints object can be:
[ {"tags":[{"value":"car"},{"value":"place"}]} , {"tags":[{"value":"van"},{"value":"place"}]} ]
what I want is to simple display unique tags in a div. It is simple, keeping a list of all displayed tags and upon getting a tag, checking if it is already in the list, and if not display it and add it to the list. Weirdly, it's not working.
The codes are:
{% set tagValues = [] %}
{% for endpoint in endpoints %}
{% for tag in endpoint["tags"]%}
{% set tagValue = tag["tag"]["value"] %}
{% if tagValue not in tagValues %}
{% set tagValues = tagValues + [tagValue] %}
<span >{{ tagValue }}</span></a>
{% endif %}
{% endfor %}
{% endfor %}
it is not working, for example, for the enpoints list above, I am getting the following output:
car place van place
is there any problem with the codes ?
I recommend creating a distinct list of tags in your View. e.g.
distinctTags = list(set([tag for endpoint in endpoints for tag in endpoint]))
and passing that to your template
{% for tag in distinctTags %}
<span >{{ tagValue }}</span></a>
{% endfor %}
this has the advantage of the distinct tag code being reusable and the code being less procedural.
my jinja knowledge is limited, but by adding tagValues to the output, it appears that it's reset after each iteration of the outer loop. I'd guess it's to do with scopes, but don't know.
My recommendation would be to pre-process your endpoints in regular python before passing to jinja

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 %}

display list value in template page using django

I need to display the value of list in template page using django. I have a variable like
data = [('dic1',),('dic2',)]
I pass the value to the template this way:
return render(request,'success.html',{'details':data})
Then in the template I need to show the value. I have used the for loop in the template like:
{% for a in data %}
{{a}}
{% endfor %}
But it displays as
('dic1',)
('dic2',)
when I need to display only the value like below
dic1
dic2
Canyone help me to find out which mistake I did ?
Thanks for your response. I jus to use like below
{% for a in data %}
{{ a.0 }}
{% endfor %}
Now it's working correctly.

Return items from RSS feed in Django Templatetags

Django noob here.
I'm trying to add RSS feed items into a django template using templatetags (with classytags).
Here's my code:
from django import template
from classytags.core import Tag
import feedparser
register = template.Library()
class ExampleTag(Tag):
name = 'exampletag'
def render_tag(self, context):
raw_feed = "example.com/feed.rss"
feed = feedparser.parse(raw_feed)
entrylist = {}
for entry in feed.entries:
entrylist[entry.title]
return entrylist
register.tag(ExampleTag)
Then, in the template I can call the ExampleTag with:
{% load my_tag %}
{% exampletag %}
This results in a KeyError at / u'The First Entry In The Feed'
If I change my code to append to a list, the template renders without error and the entire structured list is output in a single string.
This is what I'd like to do:
{% load my_tag %}
{% for item in exampletag %}
<p> {{ item }} </p>
{% endfor %}
However this just fails silently (obviously I'm not passing an interable object to the template)
Any ideas? Is this even a good way to go about doing this?
Thanks in advance.
This code looks highly suspect:
for entry in feed.entries:
entrylist[entry.title]
Shouldn't it be something like this?
for entry in feed.entries:
entrylist[entry.title] = entry # or some value
As it is right now you are trying to index into an empty dictionary and are thus getting a KeyError exception.
But I'm still not sure what you are trying to do. Here are 2 ideas that come to mind that may get you started.
Idea one: it sort of looks like you should write an inclusion tag.
Something like (untested):
#register.inclusion_tag('feed_entries.html'):
def feed_entries():
feed = feedparser.parse('example.rss')
return {'items': feed}
And in feed_entries.html
{% for item in items %}
<p> {{ item }} </p>
{% endfor %}
Then, in some random template where you want the list of items displayed:
{% load feed_tags %}
...
<p>Here are the latest entries:</p>
{% feed_entries %}
...
This is assuming feed contains a list of items you want to render somehow. Thus, whenever you use {% feed_entries %} in a template, your snippet of Python is called, it takes the returned dictionary and renders the feed_entries.html template, and the resulting HTML is placed wherever you wrote {% feed_entries %}.
Idea two: If you really want your tag to return a list of items, you could use an assignment tag:
#register.assignment_tag
def feed_entries():
return feedparser.parse('example.rss')
Then in your template you have to "catch" the result of this tag (the list of items):
{% feed_entries as items %}
{% for item in items %}
<p>{{ item }}</p>
{% endfor %}
But that means you'll have to duplicate the "as" and for-loop stuff in every template. The inclusion tag may save you typing and maintenance if you use it in many templates. But if you wanted to render the list differently in each template it would be more flexible. Say you want it in a list of <p> tags in one, but in a <ul> in another.

Categories