Nested loop in Django template
24,531
Solution 1
You can use backwards relationships.
{% for item in ingrcat %}
<h2>{{ item.name }}</h2>
<ul>
{% for ingr in item.ingredience_set.all %}
<li><a href="#" id="i{{ ingr.id }}">{{ ingr.name }}</a></li>
{% endfor %}
</ul>
{% endfor %}
See documentation:
https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward
Solution 2
Do get_queryset on obj.manytomanyfield
{% for item in ingrcat %}
<h2>{{ item.name }}</h2>
<ul>
{% for ingr in item.ingredients.get_queryset %}
<li><a href="#" id="i{{ ingr.id }}">{{ ingr.name }}</a></li>
{% endfor %}
</ul>
{% endfor %}
Related videos on Youtube
Author by
finspin
Updated on January 22, 2021Comments
-
finspin almost 3 years
I can't get my head around this. I need to somehow access the object in the parent loop but I'm not sure how. Here is what I've come up with so far. I marked the problematic area in the code with XXX:
Template:
{% for item in ingrcat %} <h2>{{ item.name }}</h2> <ul> {% for ingr in XXX %} <li><a href="#" id="i{{ ingr.id }}">{{ ingr.name }}</a></li> {% endfor %} </ul> {% endfor %}
XXX - should be a list of ingredients belonging to the ingredience category which is currently being looped through in the parent loop.
View:
def home(request): if request.user.is_authenticated(): username = request.user.username email = request.user.email foods = Food.objects.filter(user=request.user).order_by('name') ingredients = Ingredience.objects.filter(user=request.user).order_by('name') ingrcat = IngredienceCategory.objects.filter(user=request.user) context = {} for i in ingredients: context[i.category.name.lower()] = context.get(i.category.name.lower(), []) + [i] newcontext = {'foods': foods, 'ingredients': ingredients, 'ingrcat': ingrcat, 'username': username, 'email': email,} else: context = {} newcontext = {} context = dict(context.items() + newcontext.items()) return render_to_response('home.html', context, context_instance=RequestContext(request))
Models:
from django.db import models from django.contrib.auth.models import User class IngredienceCategory(models.Model): name = models.CharField(max_length=30) user = models.ForeignKey(User, null=True, blank=True) class Meta: verbose_name_plural = "Ingredience Categories" def __unicode__(self): return self.name class Ingredience(models.Model): name = models.CharField(max_length=30) category = models.ForeignKey(IngredienceCategory, null=True, blank=True) user = models.ForeignKey(User, null=True, blank=True) class Meta: verbose_name_plural = "Ingredients" def __unicode__(self): return self.name class Food(models.Model): name = models.CharField(max_length=30) ingredients = models.ManyToManyField(Ingredience) html_id = models.CharField(max_length=30, null=True, blank=True) user = models.ForeignKey(User, null=True, blank=True) class Meta: verbose_name_plural = "Foods" def __unicode__(self): return self.name
-
rantanplan about 11 yearsYou need to include the model definitions, in order to see the relationships between them.
-
finspin about 11 yearsRight. Models are now included.
-
-
finspin about 11 yearsThanks for the pointer, I didn't know you could go backwards like that! However, I'm getting template error
Could not parse the remainder: '()' from 'item.ingredience_set.all()'
. I tried some variations ofingredience_set
but couldn't make it work. -
Fozzle about 11 yearsAh yes, I was mistaken. In templates you don't use ().
{% for ingr in item.ingredience_set.all %}
should do the trick.