Django-tables2: Intuitive way to dynamically add columns

Created on 17 Apr 2012  ·  3Comments  ·  Source: jieter/django-tables2

Due to all the meta magic going on, I am currently using:

class StatsTable(tables.Table):
   class Meta:
        orderable = False
        attrs = {'class': 'tablesorter'}

    def __init__(self, form, request, *args, **kwargs):
        rf_values = form.get_values()
        rf_annotations = form.get_annotations()
        rf_filter = form.get_filter()
        rf_calculations = form.get_calculations()                  
        data = list(
            HourlyStat.objects.filter(**rf_filter).values(*rf_values).annotate(**rf_annotations).order_by('-clicks')
        ) 
        super(StatsTable, self).__init__(data, *args, **kwargs)      
        columns = rf_values + rf_annotations.keys() + rf_calculations
        for col in columns:
            self.base_columns[col] = tables.Column()     

really the only issue with me using it like this is the fact that I can't simply call super() last it has to be in the middle. I guess its because the meta class doesn't actually look for base_columns on itself but only on inherited models. Really this just seems way messier than the self.fields on django forms.

Most helpful comment

This is odd
I add dynamic columns by just appending them to self.base_columns:

self.base_columns['column_name'] = tables.Column()

One thing I found annoying is that by doing that, I modify the class attribute, not the instance attribute, so any column I add on a request, will be shown on every subsequent request to the table, the solution to real dynamic columns I found was:

class ComponenteContableColumns(tables.Table):

    """Table that shows ComponentesContables as columns."""

    a_static_columns = tables.Column()

    def __init__(self, *args, **kwargs):
        # Create a copy of base_columns to restore at the end.
        self._bc = copy.deepcopy(self.base_columns)
        # Your dynamic columns added here:
        if today is 'monday':
            self.base_columns['monday'] = tables.Column()
        if today is 'tuesday':
            self.base_columns['tuesday'] = tables.Column()
        super().__init__(*args, **kwargs)
        # restore original base_column to avoid permanent columns.
        type(self).base_columns = self._bc

All 3 comments

This is odd
I add dynamic columns by just appending them to self.base_columns:

self.base_columns['column_name'] = tables.Column()

One thing I found annoying is that by doing that, I modify the class attribute, not the instance attribute, so any column I add on a request, will be shown on every subsequent request to the table, the solution to real dynamic columns I found was:

class ComponenteContableColumns(tables.Table):

    """Table that shows ComponentesContables as columns."""

    a_static_columns = tables.Column()

    def __init__(self, *args, **kwargs):
        # Create a copy of base_columns to restore at the end.
        self._bc = copy.deepcopy(self.base_columns)
        # Your dynamic columns added here:
        if today is 'monday':
            self.base_columns['monday'] = tables.Column()
        if today is 'tuesday':
            self.base_columns['tuesday'] = tables.Column()
        super().__init__(*args, **kwargs)
        # restore original base_column to avoid permanent columns.
        type(self).base_columns = self._bc

I have the same issue as @jmfederico and have had to put his suggested hack (workaround) in place. Is there a better suggestion on how to dynamically add columns to a table? I have a table with dates from a query along the top so depending on how it is filtered it may have more or less and different dates. I couldn't work out for the life of me why sometimes we had some extra columns that weren't in the query and figured out it was this same problem.

For reference here is my table class

class ActivitySummaryTable(TableWithRawData):
    activity = tables.Column(verbose_name=_('Activity'), orderable=False)
    # the rest of the columns will be added based on the filter provided

    def __init__(self, extra_cols, *args, **kwargs):
        """Pass in a list of tuples of extra columns to add in the format (colunm_name, column)"""
        # Temporary hack taken from: https://github.com/bradleyayers/django-tables2/issues/70 to avoid the issue where
        # we got the same columns from the previous instance added back
        # Create a copy of base_columns to restore at the end.
        _bc = copy.deepcopy(self.base_columns)
        for col_name, col in extra_cols:
            self.base_columns[col_name] = col
        super(ActivitySummaryTable, self).__init__(*args, **kwargs)
        # restore original base_column to avoid permanent columns.
        type(self).base_columns = _bc

    class Meta:
        attrs = {'class': 'table'}
        order_by = ('activity',)

Example where we filter the dates and then there are 2 stray dates added at the end
image

fixed in 817d711 using the extra_columns argument

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brianmay picture brianmay  ·  6Comments

applegrew picture applegrew  ·  17Comments

mpasternak picture mpasternak  ·  9Comments

wtfrank picture wtfrank  ·  32Comments

foldedpaper picture foldedpaper  ·  6Comments