martsberger / django-pivot

A module for pivoting Django Querysets
MIT License
209 stars 16 forks source link

Example to render pivot table in template #8

Closed coler-j closed 11 months ago

coler-j commented 5 years ago

As per title, what is the best/easiest way to render the columns of the pivot table dynamically?

coler-j commented 5 years ago

Seems like there should be some helpers for this. I ended up doing something like this:

column_data = copy.deepcopy(pivot_table_data)
for d in column_data:
    del d['row_index_key']
sorted_column_keys = sorted(list(set().union(*(d.keys() for d in column_data))), reverse=True)

Then in the template:

<table>
    <thead>
        <tr>
          <th>Name</th>
           {% for key in column_keys %}
               <th>{{ key }}</th>
           {% endfor %}
         </tr>
     </thead>
     <tbody>
         {% for row in pivot_table %}
         <tr>
            <td>{{ row.row_index_key }}</td>
            {% for key in column_keys %}
                <td>{{ row|get_item:key }}</td>
            {% endfor %}
         </tr>
         {% endfor %}
       </tbody></table>

Where get_item is a template filter to get a value from a dict (the row) by key.

jaspercram commented 4 years ago

It would be great if the result of the pivot table call could be fed into django-tables2 somehow. Any idea if/how this could be possible?

martsberger commented 4 years ago

The result of the pivot table call is a values queryset with annotations or a list of dictionaries. The django-pivot library is not opinionated on what you do with this result, how you choose to render it on a template or process the data.

This can be fed into any library that handles querysets or lists of dictionaries. django-tables2 handles both just fine. You have to define a custom Table because django-tables2 uses the fields on the model by default. But, taking the first example from the django-pivot readme:

import django_tables as tables

pivot_table = pivot(ShirtSales, 'shipped', 'region', 'units')

class PivotTable(tables.Table):
    west = tables.Column()
    east = tables.Column()
    north = tables.Column()
    south = tables.Column()    
    shipped = tables.DateColumn()

    class Meta:
        model = ShirtSales

pivot_table = PivotTable(pivot_table)

And then in your template

{% load render_table from django_tables2 %}

{% render_table pivot_table %}

You can read the django-tables2 docs for how to customize rendering this.

jaspercram commented 4 years ago

This would be great, except that I don't know the columns in advance. Just like in the django-pivot readme where the columns are dates. It is unknown in advance what date columns the pivot table will get. I will have a look if I can find another django table renderer that does not require to define the columns in advance.

ReedJessen commented 4 years ago

I also would like to be able to feed the results of pivot into django-tables2 but don't know my columns ahead of time.

ReedJessen commented 4 years ago

Here is a work around that I worked up using the extra_columns parameter of the tables.Table constructor:

import django_tables as tables

class MyTable(tables.Table):
    static_column = tables.Column()

pivot_table = pivot(ShirtSales, 'shipped', 'region', 'units')

cols = [(k, tables.Column()) for k,v in pivot_table[0].items()]

mytable = MyTable(data=pivot_table, extra_columns=cols)

The mytable object is a tables2 table ready for rendering.

jaspercram commented 4 years ago

@ReedJessen Sounds great. I am going to try that. Just to be sure is holdings_pivot the same variable as pivot_table? And is cols the same variable as dynamic_cols?

Thanks

ReedJessen commented 4 years ago

@jaspercram, ah, good catch. You're right. Sorry, I updated to be consistent in the snippet above.

jaspercram commented 4 years ago

I tried it and it works indeed. The only problem I still have is that it adds the extra column static_column. And for the record, when using django-tables2, the code should be slightly different:

import django_tables2 as tables, columns

class MyTable(tables.Table):
    static_column = columns.Column()

pivot_table = pivot(ShirtSales, 'shipped', 'region', 'units')
cols = [(k, columns.Column()) for k,v in pivot_table[0].items()]
mytable = MyTable(data=pivot_table, extra_columns=cols)
hsaade-algo commented 4 years ago

@jaspercram can you plz elaborate more on where did you put the code? in Views.py or tables.py? I am having trouble figuring out how to pass a simple pivot_table to django tables and render that.

rafal-jaworski commented 4 years ago

@hsaade-algo I think this code should be in the view, because you need data to create pivot_table and you need pivot_table to create instance of MyTable. You can put MyTable to your tables.py.