How to render a python dict as an html table with vertical columns
Question: I've got a python dict with where each key corresponds to a heading, and the
list associated with each heading contains an arbitrary number of values:

    
    
    data = { 
        "heading1": ['h1-val1', 'h1-val2', 'h1-val3', ],
        "heading2": ['h2-val1', ],
        "heading3": ['h3-val1', 'h3-val2', 'h3-val3', 'h3-val4', ],
    } 
    

I need to render this in a Django template as a table, where the values are
listed vertically beneath each heading, with any missing values rendered as an
empty table cell:

    
    
    <table>
    <thead>
        <tr>
        <th>heading1</th>
        <th>heading2</th>
        <th>heading3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
        <td>h1-val1</td>
        <td>h2-val1</td>
        <td>h3-val1</td>
        </tr>
        <tr>
        <td>h1-val2</td>
        <td></td>
        <td>h3-val2</td>
        </tr>
        <tr>
        <td>h1-val3</td>
        <td></td>
        <td>h3-val3</td>
        </tr>
        <tr>
        <td></td>
        <td></td>
        <td>h3-val4</td>
        </tr>
    </tbody>
    </table>
    

What's the best way to achieve this?

My first inclination is to rearrange the original dict into a 2D matrix, and
just pass that into the template. I'm sure I'm not the first to run into this
kind of problem, though, and I'm curious how others have solved this problem.

**UPDATE:** Just for reference, here's my original solution to this problem
(which I'm not very happy with).

    
    
    # Using the data dict from the question:
    size = max(len(data['heading1']), len(data['heading2']), len(data['heading3']))
    matrix = [[None, None, None] for i in range(size)] # initialize an empty matrix
    
    # manually copy the data into the appropriate column :(
    i = 0
    for item in data['heading1']:
        matrix[i][0] = item
        i += 1
    i = 0
    for item in data['heading2']:
        matrix[i][1] = item
        i += 1
    i = 0
    for item in data['heading3']:
        matrix[i][2] = item
        i += 1
    

I then passed the matrix into the template which looked like this:

    
    
    <table>
    <thead><tr>
        <th>heading1</th>
        <th>heading2</th>
        <th>heading3</th>
    </tr></thead>
    <tbody>
    {% for row in matrix %}
        <tr>
        {% for col in row %}
            <td>{% if col %}{{ col }}{% else %}&nbsp;{% endif %}</td>
        {% endfor %}
        </tr>
    {% endfor %}
    </tbody>
    </table>
    


Answer: If we change the game a little bit, it's actually a snap to turn this around
(so long as your lists are None filled...)

    
    
    from django.template import Context, Template
    
    data = {
        "heading1": ['h1-val1', 'h1-val2', 'h1-val3', ],
        "heading2": ['h2-val1', ],
        "heading3": ['h3-val1', 'h3-val2', 'h3-val3', 'h3-val4', ],
    }
    
    # we'll need to split the headings from the data
    # rather than using keys() I'm just hard coding so I can control the order
    headings = ["heading1", "heading2", "heading3"]
    
    columns = [data[heading] for heading in headings]
    
    # get the length of the longest column
    max_len = len(max(columns, key=len))
    
    for col in columns:
        # padding the short columns with None
        col += [None,] * (max_len - len(col))
    
    # Then rotate the structure...
    rows = [[col[i] for col in columns] for i in range(max_len)]
    
    
    dj_template ="""
    <table>
    {# headings #}
        <tr>
        {% for heading in headings %}
            <th>{{ heading }}</th>
        {% endfor %}
        </tr>
    {# data #}
    {% for row in data %}
        <tr>
            {% for val in row %}
            <td>{{ val|default:'' }}</td>
            {% endfor %}
        </tr>
    {% endfor %}
    </table>
    """
    
    # finally, the code I used to render the template:
    tmpl = Template(dj_template)
    tmpl.render(Context(dict(data=rows, headings=headings)))
    

For me, this produces the following (blank lines stripped):

    
    
    <table>
        <tr>
            <th>heading1</th>
            <th>heading2</th>
            <th>heading3</th>
        </tr>
        <tr>
            <td>h1-val1</td>
            <td>h2-val1</td>
            <td>h3-val1</td>
        </tr>
        <tr>
            <td>h1-val2</td>
            <td></td>
            <td>h3-val2</td>
        </tr>
        <tr>
            <td>h1-val3</td>
            <td></td>
            <td>h3-val3</td>
        </tr>
        <tr>
            <td></td>
            <td></td>
            <td>h3-val4</td>
        </tr>
    </table>
    

