Search code examples
djangodjango-templates

create content page - filter queryset by foreignkey and render the result to Django templates -


Trying to render this structure (tree structure):

Book_1
 Books_1's Chapters
Book_2
 Books_2's Chapters
book:To Kill a Mockingbird
 itschapter:Chapter 1 - The Beginning of the Finch's
 itschapter:Chapter 2 - The Adventures of Education
 ...
book:The Sweet Hereafter
 itschapter:Chapter 1 - Dolores Driscoll
 itschapter:Chapter 2 - Billy Ansel
 ...

I have two Django models(tables) for just that: two tables with id and name columns.

# myApp/models.py
from django.db import models

# books table #
class books_DB(models.Model):
  #pk is book_id
  book_id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
  book_name = models.CharField(max_length=100)

# chapters table #
class chapters_DB(models.Model):
  #pk is chapter_id
  chapter_id = models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
  #foreign key 'book_id' from 'books_DB' 
  book_id = models.ForeignKey(books_DB, on_delete=models.CASCADE, default=None)
  chapter_name = models.CharField(max_length=100)

I tested how to get this structure in python shell

from .models import *

for x in books_DB.objects.all():
 print(x.book_name)
 for y in x.chapters_db_set.all():
   print(' ' + y.chapter_name)
To Kill a Mockingbird
 The Beginning of the Finch's
 The Adventures of Education
The Sweet Hereafter
 Dolores Driscoll
 Billy Ansel

Now I wish to render the result to a page like this

• To Kill a Mockingbird
  1. The Beginning of the Finch's
  2. The Adventures of Education
• The Sweet Hereafter
  1. Dolores Driscoll
  2. Billy Ansel
<ul class="books">

 <li class="book">To Kill a Mockingbird</li>
   <ol class="chapters">
      <li class="chapter">The Beginning of the Finch's</li>
      <li class="chapter">The Adventures of Education</li>
   </ol>

 <li class="book">The Sweet Hereafter</li>
   <ol class="chapters">
      <li class="chapter">Dolores Driscoll</li>
      <li class="chapter">Billy Ansel</li>
   </ol>

</ul>

I tried

<ul class="books">

    <!-- all_books is books_DB.objects.all() -->
    {% for x in all_books %}
    <li class="book">{{ x.book_name }}</li>
    <ol class="chapters">
        {% for y in x.chapter_db_set.all %}
            <li class="chapter">{{ y.chapter_name }}</li>
        {% endfor %}
    </ol>
    {% endfor %}

</ul>

which gives

book:To Kill a Mockingbird
book:The Sweet Hereafter

so the inner for loop for chapters returns nothing

        {% for y in x.chapter_db_set.all %}
            <li class="chapter">{{ y.chapter_name }}</li>
        {% endfor %}

but I can't seem to figure out how to use _set.all() in a template within {% %} tags and should I. Or even how to pass data filtered in views.py to the page the right way in this scenario.


Solution

  • EDITED - FORGET PREVIOUS

    your html structure seems a bit wrong.

    it should be like this:

    <ul>
        <li>
            <p>First numbered Item</p>
            <ol>
                <li>one thing</li>
                <li>two things</li>
                <li>three things</li>
            </ol>
        </li>
        <li>
            <p>Second numbered Item</p>
            <ol>
                <li>one thing</li>
                <li>two things</li>
                <li>Three things</li>
            </ol>
        </li>
    </ul>
    

    so inner ol tag is part of outer li tag

    try

    <ul class="books">
    
        <!-- all_books is books_DB.objects.all() -->
        {% for x in all_books %}
            <li class="book">
                <p>{{ x.book_name }}</p>
                <ol class="chapters">
                    {% for y in x.chapter_db_set.all %}
                        <li class="chapter">{{ y.chapter_name }}</li>
                    {% endfor %}
                </ol>
            </li>
        {% endfor %}
    </ul>