Django template variables as key for a list - django

I'm coming from this question Use variable as dictionary key in Django template
i've this context created in my view:
{'cats': {'LIST1': ['a','b','c'], 'LIST2': ['aa','bb','cc','dd'], 'LIST3': ['f','g']}}
what i want to do is to print the list title and then all the items, something like
LIST1:
- a
- b
- c
for all the lists, so i did this in my template
{% for l_name, l in cats %}
{{ l_name }}
{%for lv in l %}
{{ lv }}
{% endfor %}
{% endfor %}
and this prints only the list names, without printing out the list. where's the mistake?
thanks

If you want to iterate over keys and values, you can use:
{% for name, lst in cats.iteritems %}
....
{% endfor %}
This just calls the iteritems method of a dictionary, which returns an iterator over a list of 2-tuples.
Django's {% for %} tag documentation has some nice example of this too.

Just for the record, the problem is how the data are created. so instead of
{'cats': {'LIST1': ['a','b','c'], 'LIST2': ['aa','bb','cc','dd'], 'LIST3': ['f','g']}}
i need a list of touple so:
{'cats': [('LIST1', ['a','b','c']), ('LIST2', ['aa','bb','cc','dd']), ('LIST3', ['f','g'])]}

Related

Iterate specific dictionary values in django template

When i receive a associative array namely dictionaries in django template which as follows
"receivable_aging": {
"age5": 235114.91999999998,
"age4": 235114.91999999998,
"age3": 0,
"age2": 0,
"age1": 0 }
I tried to print like this
{% for key, value in receivable_aging.items %}
{{ value }}
{% endfor %}
I want to print age1 to age4 in ascending order. How can I achieve this without if or minimal steps.
Sort items in your views.py:
return render_to_response('page.html',
{'receivable_aging': sorted(receivable_aging.items())})
Then print them in template:
{% for key, value in receivable_aging %}
{{ value }}
{% endfor %}
Hope it helped.

Iterate through an object in Django template

In Django 1.9, I have a database table that contains car brands. I am trying to build an index (like one found at the back of a textbook) of car brands. For example:
A
Aston Martin
Audi
...
B
Bentley
BMW
...
Here is code from my view.py:
def home(request):
car_index = {}
alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z']
for letter in alphabet:
car_index[letter] = {}
car_index[letter]['title'] = letter
car_index[letter]['brands'] = Cars.objects.filter(brand__startswith = letter)
return render(request, 'cars/home.html', {'car_index':car_index})
Here is code from my home.html template:
{% for each in car_index %}
{{ each.title }}
{% for brand in each.brands %}
{{ brand.name }}<br>
{% endfor %}
{% endfor %}
In view.py, I have tried .values() in the queryset, .items() in the template context. In the template, I have tried car_index.items, each.brands.items, each.brands[0]. Nothing works. With the code above as is, I get the titles: E D X I A U H B T S N K Q Z J Y W V O L R F G P C M, but no links. (I know how to sort, but working on links first)
I have read:
https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#for
how to iterate through dictionary in a dictionary in django template?
better approach - cleaner code, apart from db effeciency:
alphabet = ['A','B','C','D','E','F','G', ..]
brands_list = []
for letter in alphabet:
letter_ = {'cars': Cars.objects.filter(brand__startswith=letter), 'letter': letter}
brands_list.append(letter_)
return render(request, 'cars/home.html', {'brands': brands_list})
template
{% for brand in brands %}
{{ brand.letter }}
{% for car in brand.cars %}
{{ car.name }}<br>
{% endfor %}
{% endfor %}
Can I dissuade you from your current approach?
You are doing a full table scan in 26 steps. If the brand column is not unique, you will find that the names get repeated. If you have millions of records you will exhaust memory. If the brand column does not have an index, you will find that the following query is very very slow:
Cars.objects.filter(brand__startswith = letter)
There is a really simple solution. That too might involve a full table scan, but at least you are executing one slow query instead of 26.
Cars.objects.raw('SELECT max(id), SubStr(brand,1,1) AS letter, brand
FROM myapp_cars GROUP BY substr(brand,1,1)')
This is with the use of raw queries. If you don't like them and happen to be fortunate enough to be on Postgresql you can use distinct to achieve the same objectively more elegantly.
I'm glad my comment helped you somehow to solve your problem.
I'm just posting it as an answer so that it may help others .
{% for each in car_index %}, just iterates out the current dict and doesn't unpack the dict of dicts which is the brands dict
As the car_index context contained a dictionary, the following would display the keys and values of the car_index dictionary and unpacks the brands dict.
{% for key,value in car_index.items %}
{{ value.title }}
{% for brand in value.brands %}
{{ brand.name }}<br>
{% endfor %}
{% endfor %}

Accessing nested list by variable in Django templates [duplicate]

I have some loop on the page and need list item depending from loop number.
When I call:
{{ mylist.1 }}
{{ mylist.2 }}
{{ mylist.3 }}
all works fine but what I really need is something like:
{% for x in somenumber|MyCustomRangeTag %}
{{ mylist.x }}
{% endfor %}
MyCustomRangeTag gives me Python range() it works and I already have x as number. So x is 1, 2, 3 etc. depending from loop number.
Is this possible and how?
This is not possible directly because Django thinks that "x" is the key to lookup in mylist - instead of the value of x. So, when x = 5, Django tries to look up mylist["x"] instead of mylist[5].
Use the following filter as workaround:
#register.filter
def lookup(d, key):
return d[key]
and use it like
{{ mylist|lookup:x }}
The slice tag in Django templates may use python's slicing code, but the syntax is unmistakably different. For instance, if you wanted to get an element of a sequence with a variable, in python you'd write something similar to the following:
>>>mylist = ["0th Element", "1th Element"]
>>>zero, one = 0, 1
>>>mylist[zero]
"0th Element"
>>>mylist[one]
"1th Element"
Using this syntax with the Django slice template tag will return a sliced list in every case, of dubious utility for getting an item of known index:
{% with "0" as zero %}
{% with "1" as one %}
{% with "2" as two %}
{{mylist|slice:zero}} {{mylist|slice:one}} {{mylist|slice:two}}
{% endwith %}
{% endwith %}
{% endwith %}
Renders to the html:
[] ["0th Element"] ["0th Element", "1th Element"]
Note the differences: you are getting the result of mylist[:x] instead of mylist[x].
Django provides enough tools to work around this. The first trick is to use explicit slices like 0:1 for your indices, and then |join:"" the resultant list into a single element. Like so:
{% with "0:1" as zero %}
{{mylist|slice:zero|join:""}}
{% endwith %}
Yields:
0th Element
This comes in particularly handy if you need to access a parent loop's index when dealing with an iterable inside a child loop:
{% for parent in parent_loop %}
{% cycle "0:1" "1:2" "2:3" as parent_loop_index silent %}
{% for child in child_loop %}
{{child|slice:parent_loop_index|join:""}}
{% endfor %}
{% endfor %}
Completed with nothing but stock parts, although I don't think Django has implemented achievements yet.
I notice that #e-satis mentioned it, but I think the built-in slice template tag deserves some love.
{{ item | slice:"2" }} #gets the third element of the list
Are you sure you can't just do:
{% for item in mylist %}
{{ item }}
{% endfor %}
With the slice filter, you can even do some customisation.
Following worked for me
{% for 1,2,3 in mylist %}
# do stuff
Just don't use brackets around 1,2,3

Determine order of iteration in django template for loop

I am populating a list in my view:
hits_object = {}
hits_object['Studio'] = hitlist('Studio',days)
hits_object['Film'] = hitlist('Film',days)
hits_object['Actor'] = hitlist('Actor',days)
hits_object['Historical Event'] = hitlist('Event',days)
hits_object['Pop Culture'] = hitlist('Pop_Culture',days)
Then I am displaying it in my template:
{% for model, hits in hits_object.items %}
{% if hits %}
<u> Most {{ model }} views in last {{ days }} days</u>
<ol>
{% for hit in hits %}
<li>{{ hit.name }} - {{ hit.count }}</li>
{% endfor %}
</ol>
</u>
{% endif %}
{% endfor %}
The problem is that the models display in a seemingly random order: first Actor, then Studio, Historical Event, Film, etc.
How can I force the for loop in the template to iterate the object in a specific order?
Dictionaries are unordered. If you need to preserve insertion order, use an ordered dict implementation - there's one in django.utils.datastructures.SortedDict, for example.
Or, since you don't seem to be using the key of the dictionary but are just iterating through, appending to a simple list would seem to be easier.
As Daniel explained, dictionaries are accessed randomly. Here is one way to do what you want:
hits_object = list()
hits_objects.append(
(hitlist('Studio',days),
hitlist('Film',days),
hitlist('Actor',days),
hitlist('Event',days),
hitlist('Pop_Culture',days))
In your view:
{% for studio,film,actor,event,pop_culture in hits_objects %}
# do something...
{% endfor %}

Get list item dynamically in django templates

I have some loop on the page and need list item depending from loop number.
When I call:
{{ mylist.1 }}
{{ mylist.2 }}
{{ mylist.3 }}
all works fine but what I really need is something like:
{% for x in somenumber|MyCustomRangeTag %}
{{ mylist.x }}
{% endfor %}
MyCustomRangeTag gives me Python range() it works and I already have x as number. So x is 1, 2, 3 etc. depending from loop number.
Is this possible and how?
This is not possible directly because Django thinks that "x" is the key to lookup in mylist - instead of the value of x. So, when x = 5, Django tries to look up mylist["x"] instead of mylist[5].
Use the following filter as workaround:
#register.filter
def lookup(d, key):
return d[key]
and use it like
{{ mylist|lookup:x }}
The slice tag in Django templates may use python's slicing code, but the syntax is unmistakably different. For instance, if you wanted to get an element of a sequence with a variable, in python you'd write something similar to the following:
>>>mylist = ["0th Element", "1th Element"]
>>>zero, one = 0, 1
>>>mylist[zero]
"0th Element"
>>>mylist[one]
"1th Element"
Using this syntax with the Django slice template tag will return a sliced list in every case, of dubious utility for getting an item of known index:
{% with "0" as zero %}
{% with "1" as one %}
{% with "2" as two %}
{{mylist|slice:zero}} {{mylist|slice:one}} {{mylist|slice:two}}
{% endwith %}
{% endwith %}
{% endwith %}
Renders to the html:
[] ["0th Element"] ["0th Element", "1th Element"]
Note the differences: you are getting the result of mylist[:x] instead of mylist[x].
Django provides enough tools to work around this. The first trick is to use explicit slices like 0:1 for your indices, and then |join:"" the resultant list into a single element. Like so:
{% with "0:1" as zero %}
{{mylist|slice:zero|join:""}}
{% endwith %}
Yields:
0th Element
This comes in particularly handy if you need to access a parent loop's index when dealing with an iterable inside a child loop:
{% for parent in parent_loop %}
{% cycle "0:1" "1:2" "2:3" as parent_loop_index silent %}
{% for child in child_loop %}
{{child|slice:parent_loop_index|join:""}}
{% endfor %}
{% endfor %}
Completed with nothing but stock parts, although I don't think Django has implemented achievements yet.
I notice that #e-satis mentioned it, but I think the built-in slice template tag deserves some love.
{{ item | slice:"2" }} #gets the third element of the list
Are you sure you can't just do:
{% for item in mylist %}
{{ item }}
{% endfor %}
With the slice filter, you can even do some customisation.
Following worked for me
{% for 1,2,3 in mylist %}
# do stuff
Just don't use brackets around 1,2,3