[Answer]-Django-tables2 render merged tables

1👍

I have a solution, but it’s not elegant.

I merge two dictionaries and build table for merged dictionary. After that i just add merged columns to the table. They are in same order as in merged dictionary. Also I’ve changed template for the table for handling merged columns.

Here is the code:

from collections import defaultdict
import django_tables2 as tables

def merge_table_dicts(labels, tables, key_column):
    merged_tables = []
    for table, label in zip(tables, labels):
        new_table = []
        for row in table:
            new_row = {}
            for key, value in row.iteritems():
                if key == key_column:
                    new_row[key] = value
                else:
                    new_row[old_key + '_' + label] = value
            new_table.append(new_row)
        merged_tables.append(new_table)
    d = defaultdict(dict)
    for l in merged_tables:
        for elem in l:
            d[elem[key_column]].update(elem)
    merged_table_dicts = d.values()
    return merged_table_dicts


def get_merged_table(labels, tables_dicts, key_column_name, merged_columns_order):
    attrs = {}
    # General options
    class Meta:
        order_by = (key_column_name,)
        template = '_merged_table.html'
        empty_text = 'No data presented'
    attrs['Meta'] = Meta
    attrs[key_column_name] = tables.Column()
    for column in merged_columns_order:
        for label in labels:
            attrs[get_merged_key(column, label)] = tables.Column(verbose_name=label)
    merged_table = type('MergedTable', (tables.Table,), attrs)
    merged_columns = []
    for merged_column_name in merged_columns_order:
        column = tables.Column(verbose_name=merged_column_name,
                               attrs={"th": {"rowspan": len(labels)}})
        merged_columns.append(column)
    merged_table.merged_columns = merged_columns

    # Merge data for table
    data = merge_table_dicts(labels, tables_dicts, key_column_name)
    return merged_table(data)

And it’s a changed part of a template:

<thead>
    <tr>
    {% with column=table.columns|first %}
        {% if column.orderable %}
        <th rowspan="2" {{ column.attrs.th.as_html }}><a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header }}</a></th>
        {% else %}
        <th rowspan="2" {{ column.attrs.th.as_html }}>{{ column.header }}</th>
        {% endif %}
    {% endwith %}
    {% for column in table.merged_columns %}
        <th colspan="{{ column.attrs.th.rowspan }}">{{ column.header }}</th>
    {% endfor %}
    </tr>
    <tr>
    {% for column in table.columns %}
        {% if not forloop.first %}
            {% if column.orderable %}
            <td {{ column.attrs.th.as_html }}><a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header }}</a></td>
            {% else %}
            <td {{ column.attrs.th.as_html }}>{{ column.header }}</td>
            {% endif %}
        {% endif %}
    {% endfor %}
    </tr>
</thead>

Leave a comment