Home > Software design >  Relational queryset not showing properly in template
Relational queryset not showing properly in template

Time:09-29

I believe is a quite basic problem, but I'm trying to render in a template all the titles for an specific page, and inside that title its corresponding text. With these models:

class Page(models.Model):
    page_title = models.CharField(_("title of the page"), max_length=50)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)

    def __str__(self):
        return self.page_title


class Category(models.Model):
    category_name = models.CharField(_("name of the category"), max_length=50)

    def __str__(self):
        return self.category_name


class Title(models.Model):
    title = models.CharField(_("titulo"), max_length=50)
    page = models.ForeignKey(Page, on_delete=models.CASCADE)

    def __str__(self):
        return self.title


class Text(models.Model):
    title = models.ForeignKey(Title, verbose_name=_("titulo de la pagina a la que pertenece"), on_delete=models.CASCADE, default='')
    content = models.TextField()

    def __str__(self):
        return f"{self.title}"

I am using this view to render the logic:

def index(request):
    pages = Page.objects.all()
    titles = Title.objects.filter(page__id=2)
    for title in titles:
        title_id = title.id
    texts = Text.objects.filter(title__id=title_id)
    context = {
        'pages' : pages,
        'titles' : titles,
        'texts' : texts,
    }
    return render(request, 'index.html', context)

But with this approach the texts only gives me the text of the last title when rendered this way in template:

{% for page in pages %}
    <h1>{{page}}</h1>
    
    {% for title in titles %}
        <h3>{{title}}</h3>
        {% for text in texts %}
        <p>{{text}}</p>   
        {% endfor %}     
    {% endfor %}

{% endfor %}

The desired rendering would be all the titles and texts were displayed like this:

Title 1

Text of title 1

Title 2

Text of title 2

Title 3

Text of title 3

For as many titles and texts there are in the database. What would be the approach for that?

Edit: the current output shows the titles correctly but the text is always the last one (in this case text 3)

Output

CodePudding user response:

The problem is in the views logic:

try this:

def index(request):
    pages = Page.objects.all()
    titles = Title.objects.filter(page__id=2)
    title_id = []
    for title in titles:
        title_id.append(title.id)
    texts = Text.objects.filter(title__id__in=title_id)
    context = {
        'pages' : pages,
        'texts' : texts,
    }
    return render(request, 'index.html', context)

Also in models.py change class Text as:

class Text(models.Model):
    title = models.ForeignKey(Title, verbose_name="titulo de la pagina a la que pertenece", on_delete=models.CASCADE, default='')
    content = models.TextField()

    def __str__(self):
        return self.content  #here

Then in template do this:

{% for page in pages %}
    <h1>{{page}}</h1>
    {{texts}}
    {% for text in texts %}
        <h3>{{text.title}}</h3>
        <p>{{text}}</p>   
    {% endfor %}
{% endfor %}

Hope this will work !

CodePudding user response:

The answer was simple as I was iterating wrong in the template. I had to use _set.all in order to retrieve the correct child elements.

{% for page in pages %}
    <h1>{{page}}</h1>
    
    {% for title in titles %}
        <h3>{{title}}</h3>
        {% for text in title.text_set.all %} # This
        <p>{{text.content}}</p>        
        {% endfor %}
    {% endfor %}

{% endfor %}
  • Related