django-tables2从hstore向表类添加动态列

时间:2016-09-13 14:24:44

标签: python django hstore django-tables2

我的一般问题是:我可以使用存储在 HStoreField (Django 1.8.9)中的数据为现有的类动态生成列 django-tables2 ?以下是一个例子,说我有一个模型:

from django.contrib.postgres import fields as pgfields

GameSession(models.Model):
    user = models.ForeignKey('profile.GamerProfile')
    game = models.ForeignKey('games.Game')
    last_achievement = models.ForeignKey('games.Achievement')
    extra_info = pgfields.HStoreField(null=True, blank=True)

现在,我说有一个表定义为:

GameSessionTable(tables.Table):
    class Meta(BaseMetaTable):
        model = GameSession
        fields = []
        orderable=False

    id = tables.LinkColumn(accessor='id', verbose_name='Id', viewname='reporting:session_stats', args=[A('id')], attrs={'a':{'target':'_blank'}})
    started = DateTimeColumn(accessor='startdata.when_started', verbose_name='Started')
    stopped = DateTimeColumn(accessor='stopdata.when_stopped', verbose_name='Stopped')
    game_name = tables.LinkColumn(accessor='game.name', verbose_name='Game name', viewname='reporting:game_stats', args=[A('mainjob.id')], attrs={'a':{'target':'_blank'}})

我希望能够为所有GameSession extra_info 列中存储的每个密钥添加列。我试图覆盖GameSessionTable类的 init ()方法,在那里我可以访问查询集,然后创建一组GameSession个对象的所有键,然后添加它们到self,然而这似乎不起作用。代码如下:

def __init__(self, data, *args, **kwargs):
    super(GameSessionTable, self).__init__(data, *args, **kwargs)

    if data:
        extra_cols=[]
        # just to be sure, check that the model has the extra_info HStore field
        if data.model._meta.get_field('extra_info'):
            extra_cols = list(set([item for q in data if q.extra_info for item in q.extra_info.keys()]))
        for col in extra_cols:
            self.columns.columns[col] = tables.Column(accessor='extra_info.%s' %col, verbose_name=col.replace("_", " ").title())

请注意,我已经看了https://spapas.github.io/2015/10/05/django-dynamic-tables-similar-models/#introduction,但它没有太多帮助,因为那里的用例与模型的字段有关,而我的情况与你的情况略有不同可以看到上面。

只是想检查,这是否可能,或者我是否必须为此数据定义完全不同的表格,或者可能使用完全不同的库,例如django-reports-builder

1 个答案:

答案 0 :(得分:1)

管理在一定程度上解决这个问题。我上面运行的代码略有错误,因此我更新它以在超类 init()运行之前运行我的代码,并更改我添加列的位置。

结果,我的 init()功能现在看起来像这样:

def __init__(self, data, *args, **kwargs):
    if data:
        extra_cols=[]
        # just to be sure, check that the model has the extra_info HStore field
        if data.model._meta.get_field('extra_info'):
            extra_cols = list(set([item for q in data if q.extra_info for item in q.extra_info.keys()]))
        for col in extra_cols:
            self.base_columns[col] = tables.Column(accessor='extra_info.%s' %col, verbose_name=col.replace("_", " ").title())

    super(GameSessionTable, self).__init__(data, *args, **kwargs)

请注意,我使用 self.base_columns 替换了 self.columns.columns (这是BoundColumn实例)。这允许超类在初始化Table类时考虑这些。

可能不是最优雅的解决方案,但它似乎对我有用。