I have a template variable product_list, which is a QuerySet of Product objects; Product objects, in turn, have a one-to-many field of Track objects (reverse mapped from Track, of course), which is possible to be empty. I want to create a list of Tracks, grouped by Products like this:
{% for product in product_list %}
{% if this is not the first product with tracks %}
<li class="separator"></li>
{% endif %}
{% for track in product.tracks %}
<li>{{track}}</li>
{% endfor %}
{% endfor %}
The question is, what should I write of if this is not the first product with tracks? I tried ifchanged product but it inserts a separator even on the first iteration (as it changes from "" to "someproduct"). forloop.counter is also not usable here, as it is possible that the first two products won’t have tracks.
One workaround could be to change product_list to track_list like this:
track_list = Track.objects.order_by('product__name')
so I can indeed use ifchanged. It is doable in my case, but I’m still interested in a solution for my first method.
You should compose the condition. It looks simple, perhaps is not this that your are asking for.
{% for product in product_list %}
{% if not forloop.first and product.tracks %}
<li class="separator"></li>
{% endif %}
{% for track in product.tracks %}
<li>{{track}}</li>
{% endfor %}
{% endfor %}
If this is not a solution for you, I suggest to you to cook data on view and send ready to be parse to template, more easy.
{% for product in product_list %}
{% if product.should_have_separator %}
<li class="separator"></li>
{% endif %}
{% for track in product.tracks %}
<li>{{track}}</li>
{% endfor %}
{% endfor %}
In your view append should_have_separator field dynamically to products should have it:
product_list = Product.objects.....
is_the_first_product = True
for product in product_list:
is_the_first_product_with_tracks = ( is_the_first_product
and bool( product.tracks ) )
product.should_have_separator = not is_the_first_product_with_tracks
is_the_first_product = False
Related
category = ['cat1','cat2','cat3']
inventory = CurrentInventory.objects.all()
for cats in categories
inventorybycat = inventory.filter(category =cats)
setofinventories.append(inventorybycat)
dictofstuff = [zip(setofinventories,categories)]
context = {
'setofinventories':setofinventories
'category':category
'dictofstuff':dictofstuff
}
In views.py above this loop creates a list of objects per each category.
In the template below this loop prints a filtered object list per every item in the category list.
{% for inventory in setofinventories%}
{% for item in inventory %}
{{ item.category }}
{{ item.productName }}
{% endfor %}
{% endfor %}
The only thing I am missing is I do not now how to reference the category in the template. I pass the whole list in context, but {{category{{forloop.counter}}}} is not a valid statement.
I would either like to use zip(category,setofinventories) to pass these two items together,
or create a category model, filter by that model and then I can reference that model by item?
If I zip these items dictofstuff = [zip(setofinventories,categories)]
How do I reference the category in the template?
{% for inventory,categories in dictofstuff %}
{% for inventory in setofinventories%}
{% for item in inventory %}
{{ item.quantity }}
{{ item.productName }}
{% endfor %}
{% endfor %}
{% endfor %}
Returns Error: "Need 2 values to unpack in for loop: got 1."
If i right understand you, you want to print category only one time.
In your case:
{% for inventory in setofinventories%}
{% ifchanged inventory.category %}
{{ inventory.category }}
{% endifchanged %}
{% for item in inventory %}
{{ item.quantity }}
{{ item.productName }}
{% endfor %}
{% endfor %}
i use ifchanged, more here:
https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#ifchanged
in views i zipped this to a *listofstuff. Forgive the nomenclature.
dictofstuff = [zip(categories,setofinventories)]
in template. Again, forgive bad nomenclature. I should go back and rename these but it works.
{% for category in dictofstuff %}
{% for item in category %}
{{item.0}}
{% for stuff in item %}
{% for thing in stuff %}
{{thing.productId}}{{thing.productName}}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
Is possible to get the last n items in the Django model, using the reverse relationship.
{% for brand in brands %}
{% for product in brand.product_set.all %}
{% endfor %}
{% endfor %}
I am tried in this way, But it prints all things. But want only last 3 items
You can make use of the |slice template tag [Django-doc] to slice the collection with:
{% for brand in brands %}
{% for product in brand.product_set.reverse|slice:":3" %}
…
{% endfor %}
{% endfor %}
So I am requesting spot price from cex API, it returns something like this
{"data":[{"amount: "67000.0", "base": "BTC", "currency": "USD"}]} of course there is more than one returned so I want to loop over it.
In my views.py I am passing it into my context 'price': price. Then inside of my .html file I have a list with a for loop for example:
<ul>
{% for x in price %}
<li>{{ x }}</li>
{% endfor %}
</ul>
Then when I open my .html page I get data But what I'd like to be able to do is make a table where I have three columns to show the amount, base and currency. I am unsure on how to extract this data individualy?
You can enumerate over the .values of price, and then enumerate over the dictionaries in that list with:
<table>
{% for vs in price.values %}
{% for v in vs %}
<tr><td>{{ v.amount }}</td><td>{{ v.base }}</td><td>{{ v.currency }}</td></tr>
{% endfor %}
{% endfor %}
</table>
In Django templates, you can access to dictionary items with a expresión like {{ dictionary.key }}
<ul>
{% for x in price %}
<li>{{ x.amount }}</li>
{% endfor %}
</ul>
See the docs on https://docs.djangoproject.com/en/3.2/ref/templates/api/#variables-and-lookups
I'm passing a queryset of people to my django template, some of which have been assigned a "seat" and others that haven't. Seats can be assigned to no one and therefore remain empty. For each seat, I want the template to loop through the queryset looking for someone in that seat. If the for loop doesn't find anyone for that seat, I want them to render an empty seat. Here is what I was thinking:
{% for person in people %}
{% if person.seat_num = 1 %}
<div class="filled_seat"></div>
{% endif %}
{% empty %}
<div class="empty_seat"></div>
{% endfor %}
Except I realize that {% empty %} is only triggered if the set being iterated through is empty, whereas I need to have a default if the seat is not found (aka nothing in the set survives the "if" condition.
Yes, because for...empty works like that. It basically can't know if your seat is empty or not, for that you need to implement your own logic.
I don't know the details of your model, but guessing from your example you need to do something like this:
{% for person in people %}
{% if person.seat_num = 0 %}
<div class="empty_seat"></div>
{% else %}
<div class="filled_seat"></div>
{% endif %}
{% endfor %}
John Gordon's comment made me realize I shouldn't try to do too much in the template itself. In the view I created a list called "seats" and filled the appropriate seats, and then passed it to the template:
seats = []
for n in range(4):
try:
seats.append(students.objects.get(seat_num=n+1))
except:
seats.append(None)
I then used a for loop to cycle through the seats one at a time and check if that seat is filled and then generate the appropriate div:
{% for seat in seats %}
<td>
{% if seat %}
<div class="filled_seat"></div>
{% else %}
<div class="empty_seat"></div>
{% endif %}
</td>
{% endfor %}
Let me try to explain what I want to achieve by a small example application. It is a shopping list application that lets you add predefined Items to your ShoppingList as Groceries. The smart thing would be that every Item is related to a Store.
When I am done adding groceries to my shopping list, I should be able to see my shopping list with the groceries organized (grouped) by their Store. Something like:
How would I create a view and template to group and display this shopping list?
For example: this is how I would display the full inventory of all stores:
#views.py
store_list = Store.objects.all()
#template.html
{% for store in store_list %}
<div>{{store}}
<ul>
{% for item in store.item_set.all %}
<li>{{item}}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
That won't work for my shopping list, but I am really looking for something equally powerful / elegant....
What about the built in regroup template tag?
{% regroup item.objects.all by store as store_groups %}
<ul>
{% for store_group in store_groups %}
<li>{{ store_group.grouper }}
<ul>
{% for item in store_group.list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Do the grouping in the backend of the view instead of the template.
In your view, create a dictionary like this:
sorted_groceries = {
store1 : [item1, item2],
store2 : [item3, item4],
}
which can be done with some code resembling this pseudo-code:
sorted_groceries = {}
for item in shopping cart:
try:
sorted_groceries[item.store].append(item)
except KeyError:
sorted_groceries[item.store] = [item]
then add it to your context and have your template look like this:
{% for store, items in sorted_groceries.items %}
<div>{{store}}
<ul>
{% for item in items %}
<li>{{item}}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
How about using ifchanged https://docs.djangoproject.com/en/1.7/ref/templates/builtins/#ifchanged
Assuming shopping_list is sorted by store:
{% for item in shopping_list %}
{% ifchanged %}<h3>{{ item.store.name }}</h3>{% endifchanged %}
{{ item.name }}
{% endfor %}