Question

I have a set of imported bank account entries that are oredered by date and sequence number within each date.

I'm using django-tables2 to display the data, to which I'm adding a running total column that I calculate before rendering the view.

To do this I'm trying to add a field to the query set with the following code:

import django_tables2 as tables
from django_tables2 import RequestConfig
from .models import Bank, BankImportFile, ImportFileEntry
... other imports

class BankListingTable(tables.Table):
    memo = tables.Column(verbose_name = 'Description')
    total = tables.Column(verbose_name = 'Running Total')
    class Meta:
        model = ImportFileEntry
        attrs = {'class': 'paleblue'}

def bank_listing(request, bankname):
    bank = get_object_or_404(Bank, pk=bankname)
    qs = ImportFileEntry.objects.filter(account=Bank(bank)).order_by('date', 'seq')
    total = 0
    for row in qs:
        total += row.amount
        row.total = total
    table =  BankListingTable(qs)
    RequestConfig(request).configure(table)
    return render(request, 'banking/bank_transactions.html', {'table': table, 'bank': bank}) 

If I step through this code in pdb I can examine both row.total and qs[<row number>].total and they appear to have the correct data.

Yet in the rendered table all I get in the total column is --

If I convert my queryset to a list and leave everything else unchanged it works:

def bank_listing(request, bankname):
    bank = get_object_or_404(Bank, pk=bankname)
    qs = ImportFileEntry.objects.filter(account=Bank(bank)).order_by('date', 'seq')
    qs = list(qs)    # ADDED THIS LINE AND IT WORKS
    total = 0
    for row in qs:
        total += row.amount
        row.total = total
    table =  BankListingTable(qs)
    RequestConfig(request).configure(table)
    return render(request, 'banking/bank_transactions.html', {'table': table, 'bank': bank}) 

My queryset is large as it is a 9-year history of a business bank account so it seems very inefficient to copy it to a list.

I've seen other examples on StackOverflow that seem to imply my original code should work and pdb testing implies it should. Is this something in django-tables2?

Was it helpful?

Solution

As I said in my comment, what you did is working in my case. However, I wouldn't recommend evaluating the query with the for loop since this will load your queryset to memory (it actually has the same effect as using list). Instead, I'd recommend adding an extra row to your query that would contain the running sum.

To do do that you should use the extra queryset method to add the extra field to your queryset. To find out how to get the running total with SQL you can check the answer to this question: How to get running sum of a column in sql server

Also, since you mention that your queryset is large you should add pagination to your table -- and you will not benefit from pagination if you evaluate your queryset with the for-loop. Feel free to ask again if you have trouble implementing the extra() method.

Update: To answer OP's comment (I am not sure about the names of your tables & fields but I'll make a guess:

SELECT amount, (
    select sum(amount) FROM ImportFileEntry ife1 where ife1.date < ife.date
  ) + (
    select sum(amount) FROM ImportFileEntry ife2 where ife2.date = ife.date and ife2.seq < ife.seq
  ) as running_total  FROM ImportFileEntry ife order by ife.date, ife.seq

One (complex) query -- the as running_total would be what the extra() queryset method would create :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top