Search code examples
djangodjango-modelsforeign-keysnested-loopsone-to-many

Nested loop for foreign key in Django


Newby to Django here. I need to list some music genres and their subgenres. I got the genres just fine, but I'm not sure how to list the subgenres.

This is my model:

class Genre(models.Model):
    genre_id = models.AutoField(primary_key=True)
    code = models.CharField(unique=True, max_length=4)
    description = models.CharField(max_length=25, blank=False, null=False)

    class Meta:
        managed = False
        db_table = 'genre'
        db_table_comment = 'Music genre catalog'

    def __str__(self):
        return self.description

class Subgenre(models.Model):
    subgenre_id = models.AutoField(primary_key=True)
    code = models.CharField(unique=True, max_length=6)
    description = models.CharField(max_length=25, blank=False, null=False)
    genre = models.ForeignKey(Genre, on_delete=models.CASCADE)

    class Meta:
        managed = False
        db_table = 'subgenre'
        db_table_comment = 'Music subgenre catalog'

    def __str__(self):
        return self.description

This is what I have in views.py:

def new_playlist(request):
    genres = Genre.objects.all().order_by('description')
    subgenres = Subgenre.objects.all()
    context = { 'genres':genres, 'subgenres':subgenres }
    return render(request,"applications/ecommerce/playlists/new-playlist.html",context)

And this is my HTML code:

{% for genre in genres %}

<div class="card">
   <div class="card-header">
      <h5 class="mb-0">{{genre.description}}</h5>
   </div>
   <div class="card-body">

      {% for subgenre in subgenres.genre.all %}

      <div class="row">
         <label>{{subgenre.description}}</label>
      </div>

      {% endfor %}

   </div>
</div>

{% endfor %}

Solution

  • You should do this in the opposite direction:

    {% for genre in genres %}
    <div class="card">
       <div class="card-header">
          <h5 class="mb-0">{{ genre.description }}</h5>
       </div>
       <div class="card-body">
          {% for subgenre in genre.subgenre_set.all %}
          <div class="row">
             <label>{{ subgenre.description }}</label>
          </div>
          {% endfor %}
       </div>
    </div>
    {% endfor %}

    and as view:

    def new_playlist(request):
        genres = Genre.objects.prefetch_related('subgenre_set').order_by(
            'description'
        )
        context = {'genres': genres}
        return render(
            request, 'applications/ecommerce/playlists/new-playlist.html', context
        )