0

I need to create a custom table in django template as below:

    <table>
    <tr>
        <td>
        </td>
        <td>
        </td>
        <td>
        </td>
    </tr>
    <tr>
        <td>
        </td>
        <td>
        </td>
        <td>
        </td>
    </tr>
    <tr>
        <td>
        </td>
        <td>
        </td>
        <td>
        </td>
    </tr>
</table>

i.e I want to add new tr tag after every 3 td tags. I tried applying logic using {{forloop.counter|divisibleby:4}}. I tried something like below but it didn't generated desired results.

{% for items in range(5) %}
    {% if forloop.counter ==1 or forloop.counter|divisibleby:4 %}\
    <tr>
    {% endif %}
    <td>name</td>

    {% if forloop.counter|divisibleby:4 %}
        </tr>
    {% endif %}
    </tr>
{% endfor %} 

but it is obviously not correct solution. Update: It is generating something like below:Output Where each image is td tag

4
  • can you add a screenshot of what the output currently looks like and do a manual mockup of what you want it to look like. This will help me see what you are trying to achieve Commented Aug 9, 2016 at 13:40
  • @nkhumphreys I have added an image for output I am getting. Commented Aug 9, 2016 at 13:46
  • is range a custom template tag? Commented Aug 9, 2016 at 13:56
  • I have mention it as my object contain 5 elements. So for generalization I mention range(5) this will run for loop for 5 times. Commented Aug 9, 2016 at 13:59

2 Answers 2

2

This part is not evaluating to true for the correct numbers:

{% if forloop.counter ==1 or forloop.counter|divisibleby:4 %}

This is gonna evaluate to true when counter is 1, 4, 8, 12, etc. Not every 3 numbers, but every four numbers. Instead, use forloop.counter0, like so:

{% if forloop.counter0|divisibleby:3 %}

forloop.counter0 starts at 0, so it's gonna be divisible by 3 at 0, 3, 6, 9, etc just like you want.

There is another problem with your code here:

{% if forloop.counter|divisibleby:4 %}
    </tr>
{% endif %}
</tr>

If you only want the tag to be closed after every third element, then remove the one outside the if condition. Also, you're adding the closing tag in the wrong parts. It's supposed to be one element before you open the tag again, so at the 3rd element, 6th element, etc. For this you can still use the forloop.counter like so:

{% if forloop.counter|divisibleby:3 %}
    </tr>
{% endif %}

overall, your code should look like this:

{% for items in range(5) %}
    {% if forloop.counter0|divisibleby:3 %}
        <tr>
    {% endif %}
    <td>name</td>
    {% if forloop.counter|divisibleby:3 %}
        </tr>
    {% endif %}
{% endfor %}
</tr>

If you're using an unknown nbr number of items instead of 5, just substitute the </tr> tag outside the forloop for

{% if not nbr|divisibleby:3 %}
    </tr>
{% endif %}

so that you won't have two </tr>s if one was added at the last iteration of the for loop.

Sign up to request clarification or add additional context in comments.

4 Comments

@Simer I added a note in the end for if you're using a variable number of items
what is 'nbr' in your solution?
@Simer total number of items. So if you're using {% for items in range(nbr) %} then use that piece in the end, instead of just </tr>. or if you're using {% for items in my_queryset %} instead of range, just substitute nbr for my_queryset.count
Thanks for such a great answer.
1

So this is because you are inserting <tr> AND </tr> if the forloop counter is divisible by 4. You are also inserting <tr> if the forloop counter is 1. So the first row works, the second row will insert the opening and closing tags (because the forloop counter is still divisible by 4). Your logic is off.

I think you want:

<table> {% for items in range(5) %} {% if forloop.counter == 1 %} <tr> {% endif %} <td>name</td> {% if forloop.counter|divisibleby:4 %} </tr><tr> {% endif %} {% endfor %} </tr> </table>

6 Comments

Thank you for your solution @nkhumphreys. I will try this one also. For now I have selected solution of dietbacon as it seems bit simpler and optimized. thanks for your efforts.
Yeh dietbacon's solution is good. I don't think it particularly matters whether you start your index at 1 or 0. I am purist so prefer to start at 0 but I did not want to confuse the answer. The important thing is to get the logic for where to insert the tags correct
@nkhumphreys This solution is ok. It works fine for 5 items, but it breaks if you have more than 7 items, as it's gonna start dividing the items 4 by 4.
correct, but you you change the second if statement to divisibleby:3 then this solution works fine even with an index starting from 1
Looking closer now, won't it have 4 items even in the first row instead of 3? <tr> will close when counter is 4, so you're gonna have the item 4 times before closing for the first time. If you change it to divisibleby:3 then it works, but you'll have an empty row in the end if the total number of items is divisible by 3.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.