Pedro Assunção

Django template filter: Show list of objects as table with fixed number of columns

I recently ran into the following problem: I needed to be able to display a list of users in a table that had a maximum of X columns. Since I could not find the solution on the Internet I decided to give it a try and here is my resulting template filter to do it:

def tablecols(data, cols):
    rows = []
    row = []
    index = 0
    for user in data:
        row.append(user)
        index = index + 1
        if index % cols == 0:
            rows.append(row)
            row = []
    # Still stuff missing?
    if len(row) > 0:
        rows.append(row)
    return rows
register.filter_function(tablecols)

Then you can use it in your templates like so:

<table>
{% for row in members|tablecols:5 %}
    <tr>
    {% for member in row %}
        <td>
            {% show_simple_profile member user %}
        </td>
    {% endfor %}
    </tr>
{% endfor %}
</table>

It will break down the “members” list into a list of lists, each of the first being a group of (in this case) 5 users max.

Have fun :)

Related:

  1. [Django] Dynamic redirection after login Here’s how to redirect to the login page in django,...
  2. Django: Reverse HTTP redirect with parameters Here’s how to, from a view, redirect to another URL...


Categorised as: code snipplets, computers, software development, tips


20 Comments

  1. Serge says:

    As far as I understand the code, the table generated will render the list from left to right first and then from top to bottom. Often you need the opposite, especially if you have sorted data – say, list of countries. Basically, you will want just one row in a table where the first column has the first chunk of the list and so on.

    • nocivus says:

      Not sure i understand what you said. Can you explain it with a more explicit example?

      • Reuben says:

        I think what he means is that sometimes you want a list of columns with the alphabetization by column like this:

        AAA BBB CCC
        AAA BBB CCC
        AAA BBB CCC

        Instead of:

        AAA AAA AAA
        BBB BBB BBB
        CCC CCC CCC

        So it's basically vertical alpha instead of horizontal alpha.

        • nocivus says:

          I see. However my example doesn't do either :)

          It does:

          AAAAB
          BBCCC
          CDDEE
          EEEFG
          and so on, depending on the sorting you have on the data (alphabetical in this case).

          To do that, i would use a dictionary where the key is the letter of the alphabet and then show them accordingly.

          • Reuben says:

            Sorry, I meant my second example to be exactly what yours does. I just didn't convey it quite right. So whereas yours does:

            AAAAB
            BBCCC
            CDDEE
            EEEFG

            The other way would be this, which I'm not sure how to do in a django template.

            ABC
            ABD
            ACD
            BCD

          • nocivus says:

            Same here, i haven't touched Django in about 3 years (converted to Rails in the meantime ;) ). Wish i could help, but i'm in the middle of 3-4 projects now, and my time is really scarce :(

  2. Daniel says:

    Nearly a year later, and I've found this very useful, thank you :-)

  3. ypocat says:

    rows = [ data[v:v+cols] for v in range(0,len(data),cols) ]

    fixed! :-)

    • nocivus says:

      Thanks for the one liner. My main point was to express the creation of a template filter, but your solution for the filter implementation code is by far simpler :)

      • ypocat says:

        i know, i just like to be a smartass, and i know you know that:)
        but python really allows to write basic data manipulation in 1/10th of the space of Java-like languages, and due to the smaller space taken, the code is then also better readable and manageable, at least in my view.
        the huge downside is that the compiler doesn't tell you much about broken code – you simply have to run all the branches to make sure.. which on the other hand is good because it forces you to test your code properly…
        anyway.. i've switched from Google App Engine Java to Python some time ago, and never looked back since – but this may also be because of the GAE limitations – the stuff you can do there is usually quite simple, and Python is OK for that.

  4. Christian says:

    Perhaps by now there is a better way to do this, but I found it useful. Thanks.

    I want my tables to have the same number of columns on every row…

    # Still stuff missing?
    # see how many are missing and add empty elements to complete the row
    if len(row) > 0:
    remaining = len(row)
    to_add = cols – remaining
    for c in range(to_add):
    row.append([])

    rows.append(row)

    return rows

  5. EJ says:

    Fantastic, thank you

  6. joshua says:

    Yay! Just what I needed. Thanks.

  7. Scot Hacker says:

    Oh – except for the last line, which should be:

    register.filter('tablecols', tablecols)

    • nocivus says:

      Actually it works on my environment without the name. I think Django reverts to the function name if you don't provide one ;)

  8. Scot Hacker says:

    Thanks much, works perfectly. And this is WAY cleaner and shorter than the example shown in the Django Wiki : http://code.djangoproject.com/wiki/ColumnizeTag

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>