metraon
metraon

Reputation: 1259

Generate a multiple row/column table with Django from a list of dictionaries

I have this list which is made of multiple dictionaries from a query with Django :

Its an aggregation of statistics for multiple music instruments on each session tough in a musical school.

[{'count': 13, 'session': 1, 'instrument': u'Piano'}, {'count': 4, 'session': 1, 'instrument': u'Cello'}, {'count': 2, 'session': 1, 'instrument': u'Violin'}, {'count': 14, 'session': 2, 'instrument': u'Piano'}, {'count': 1, 'session': 4, 'instrument': u'Cello'}]

How can I loop this through to make a table with 4 columns and n rows, knowing that there will be always 4 sessions but a n number of intruments ?

What I tried almost output what I want (my template):

        <table class="table">
        <thead>
        <tr>
            <th>Session 1</th>
            <th>Session 2</th>
            <th>Session 3</th>
            <th>Session 4</th>
        </tr>
        </thead>
        {% for stat in stats_instrument %}
                {% if stat.session == 1 %}
                <tr><td>{{ stat.instrument }} {{ stat.count }}</td></tr>
                {% endif %}
        {% endfor %}
        {% for stat in stats_instrument %}
                {% if stat.session == 2 %}
                <tr><td></td><td>{{ stat.instrument }} {{ stat.count }}</td></tr>
                {% endif %}
        {% endfor %}
     ...
    </table>

The actual output is :

|Session 1| Session 2| Session 3| Session 4|
|Piano 13 |
|Cello 4  |
|Violin 2 |
|         | Piano 14 |
|         |          |           | Cello 1 |

What I want is more like :

|Session 1| Session 2| Session 3| Session 4|
|Piano 13 | Piano 14 |          | Cello 1  |
|Cello 4  |
|Violin 2 |

I see 3 problems.

  1. The instruments are not the same at each session, so piano could be teached at sessions 1-2-3.
  2. The sessions dont have the same numbers of instruments, session 1 can have about 5 intruments and session 3 about 10 instruments.
  3. I am looping multiple times the same data and it seems not very efficient.

Should I make 4 tables and put something like an inline-block ?

Upvotes: 1

Views: 1232

Answers (1)

Alex Lord Mordor
Alex Lord Mordor

Reputation: 3040

You can order your table in your view first and then give a simple ordered list to the template.

first group them by session number

sessions = [{'count': 13, 'session': 1, 'instrument': u'Piano'}, {'count': 4, 'session': 1, 'instrument': u'Cello'}, {'count': 2, 'session': 1, 'instrument': u'Violin'}, {'count': 14, 'session': 2, 'instrument': u'Piano'}, {'count': 1, 'session': 4, 'instrument': u'Cello'}]

values = set(map(lambda x:x['session'], sessions))
grouped_sessions = [[y for y in sessions if y['session']==x] for x in values]

then you should have something like:

[[{'count': 13, 'session': 1, 'instrument': u'Piano'}, {'count': 4, 'session': 1, 'instrument': u'Cello'}, {'count': 2, 'session': 1, 'instrument': u'Violin'}],[{'count': 14, 'session': 2, 'instrument': u'Piano'}],[{'count': 1, 'session': 4, 'instrument': u'Cello'}]]

now in your template do a for-loop inside a for-loop like:

<table><thead>...</thead><tbody>
<tr>
{% for g in grouped_sessions %}
    <td><table>
    {% for s in g %}
     <tr><td>{{s.instrument}} {{s.count}}</td></tr>
    {% endfor %}
    </table></td>
{% endfor %}
</tr>

This will create many nested tables but visually it does the work.

Hope it helps.

Upvotes: 2

Related Questions