Reputation: 1085
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 %}
<a href="{{ brand.link }}">{{ brand.name }}</a><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?
Upvotes: 4
Views: 21404
Reputation: 719
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 %}
<a href="{{ brand.link }}">{{ brand.name }}</a><br>
{% endfor %}
{% endfor %}
Upvotes: 1
Reputation: 37934
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 %}
<a href="{{ car.link }}">{{ car.name }}</a><br>
{% endfor %}
{% endfor %}
Upvotes: 4
Reputation: 53774
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.
Upvotes: 2