For-looping three columns per row in Django template
Asked Answered
C

3

5

I'm trying to retrieve data from the database and render it in rows of three columns. I've tried as many methods as I could find, finally it seemed to be rendering with this code:

<div class='container'>
    <div class="row">
    {% for category in categories %}
    {% if not forloop.counter0|divisibleby:"3" %}
        <div class="col-6 col-md-4">
            <h3>{{category.category_name}}</h3>
            {% for page in category.page_set.all %}
            <p>{{page.page_title}}</p>                 
            {% endfor %}
        </div>  
    {% else %}
    <div class="row">
        <div class="col-6 col-md-4">
            <h3>{{category.category_name}}</h3>
            {% for page in category.page_set.all %}
            <p>{{page.page_title}}</p>                 
            {% endfor %}
        </div> 
    {% endif %} 
    {% endfor %}
</div>

It renders the elements in three columns but the columns are not aligned, and when checking the HTML, the 'row' class is the same for all the rows (giving it an id and checking by CSS), so I guess there's something I'm doing wrong.

I'd like to get an output like:

Category1 - Category2 - Category3

Category4 - Category5 - Category6

With the 'page' objects of each category underneath.

The data is rendering OK, the view is simple (just getting all the Category objects). I just need this kind of data rendering in different rows of 3 columns. I've tried the divisibleby method, but I guess I'm still missing something out. What would be the best approach?

Cecilacecile answered 26/10, 2022 at 5:34 Comment(2)
Assuming this comes with a template render and a context, why not add a label/note/flag every 3 items or group them before rendering. It seems way simpler, though not pure template-logic segregation.Picrotoxin
Thanks for you comment. Could you explain a little bit more what do you mean? I thought about preparing the content in the view to be rendered more easily but couldn't really think of anything that worked as I wanted.Cecilacecile
F
4

You have to use counter0 in the if around open row div tag. Then you have to use counter in an if around close row div tag. Because counter0 starts with 0 and counter starts with 1. So a new row div tag is opened on 0, 3, 9, 12. And a created row div tag is closed on 2, 5, 8, 11.

<div class='container'>
{% for category in categories %}
{% if not forloop.counter0|divisibleby:"3" %}
<div class="row">
{% endif %} 
    <div class="col-6 col-md-4">
        <h3>{{category.category_name}}</h3>
        {% for page in category.page_set.all %}
        <p>{{page.page_title}}</p>                 
        {% endfor %}
    </div>  
{% if not forloop.counter|divisibleby:"3" %}
</div> 
{% endif %} 
{% endfor %}
Forbade answered 31/3, 2023 at 21:48 Comment(0)
C
3

There was a syntax error that made it render incorrectly, the following code renders correctly:

<section class="bg-light appear-animation h-100" data-appear-animation="fadeIn">
    <div class='container'>
        <div class="row">
        {% for category in categories %}
        {% if forloop.counter0|divisibleby:"3" %}
        </div>
        <div class="row">
            <div class="col-6 col-md-4">
                <h3>{{category.category_name}}</h3>
                {% for page in category.page_set.all %}
                <p>{{page.page_title}}</p>                 
                {% endfor %}
            </div>  
        {% else %}
            <div class="col-6 col-md-4">
                <h3>{{category.category_name}}</h3>
                {% for page in category.page_set.all %}
                <p>{{page.page_title}}</p>                 
                {% endfor %}
            </div> 
        {% endif %} 
        {% endfor %}
    </div>
</section>
Cecilacecile answered 26/10, 2022 at 5:47 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Fabricant
A
0

The above answer by @George Lords of Castle was on the right track, using the forloop.counter0, but it didn't quite work for me because of the negation in the if statements; also, I added 1 to the forloop.counter0 to get the right closing tag for the row after the third column. Here is what worked for me:

<div class='container'>
{% for category in categories %}
    {% if forloop.counter0|divisibleby:"3" %}
    <div class="row">
    {% endif %}
        <div class="col">
            <h3>{{category.category_name}}</h3>
            {% for page in category.page_set.all %}
                <p>{{page.page_title}}</p>                 
            {% endfor %}
        </div>
    {% if forloop.counter0|add:"1"|divisibleby:"3" %}
    </div>
    {% endif %} 
{% endfor %}
</div>
Anthropology answered 9/7 at 23:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.