Question

I use django-tables2 and have following table, which is populated by generated dictionary:

class SimpleStatTable(tables.Table):
    Metric = tables.Column(accessor='metric')
    Qty = tables.Column(accessor='qty')
    Min = tables.Column(accessor='min')
    Avg = tables.Column(accessor='avg')
    Max = tables.Column(accessor='max')

    def __init__(self, data, label=None, **kwargs):
        self.label = label
        super(SimpleStatTable, self).__init__(data, **kwargs)

    class Meta:
        order_by = ('Metric',)
        empty_text = 'No data presented'

I want to render merged table of a few SimpleStatTable tables. Is it possible with django-tables2? I like django-tables2 features, such as sorting

I have a small example of desired tables.

I suppose i need to generate class for merged table dynamically like here, but how can i add additional merged column?

Was it helpful?

Solution

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>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top