Call Overmortal now at 1 (540) 491-0374 or for more information!

Making Multi-Column Tables from a QuerySet in Django Templates

When I first got started programming in the Django framework, Django was still relatively new. As such, documentation was scarce. It look long hours of searching to often find complete solutions to complex problems. Sometimes, it even took a large chunk of time to find simple solutions to small problems. One small problem new Django users often run into is how to create a multi-column table structure in a template page. Django's template language is very strict and does not want you injecting code galore in your markup. As a result, this strictness often forces you to find a better way to code.

A great solution for this problem was posted by Ned Batchelder in a Google Groups forum for Django users. I'm going to re-post that information here for archival purposes.

Ned posted:

If your data is in the 'data' context variable, then try this:

        <table>
        {% for d in data %}
            {% if forloop.counter0|divisibleby:"2" %}<tr>{% endif %}
            <td>{{d}}</td>
            {% if forloop.counter|divisibleby:"2" %}</tr>{% endif %}
        {% endfor %}
        {% if data|length|divisibleby:"2" %}{% else %}<td> </td></tr>{% endif %}
        </table>

It's a little awkward, and doesn't generalize to more than two columns, but it does produce properly structured HTML.

If you're willing to add some code to your view, you can get more columns:

In the view:

    context['data'] = data
    ncols = 3
    for i, d in enumerate(data):
        d.firstcol = (i % ncols == 0)
        d.lastcol = (i % ncols == ncols-1)
    context['data_blanks'] = [None]*((ncols-len(data)%ncols)%ncols)

In the template:

        <table>
        {% for d in data %}
            {% if d.firstcol %}<tr>{% endif %}
            <td>{{d}}</td>
            {% if d.lastcol %}</tr>{% endif %}
        {% endfor %}
        {% for blank in data_blanks %}<td> </td>{% endfor %}
        {% if data_blanks %}</tr>{% endif %}
        </table>

The important thing to remember about the second implementation is that it manipulates the context variable. You'll have to make sure your view imports Context from the django.template module and also instantiates the context variable by doing something like context = Context() inside the view function that uses the implementation.

At Overmortal, we tend to use the second implementation above - even if we're only using two columns - as it leaves a cleaner, more readable look.