Changeset 3f1e074 for remit


Ignore:
Timestamp:
Mar 24, 2010, 6:34:54 AM (15 years ago)
Author:
Alex Dehnert <adehnert@…>
Branches:
master, client
Children:
13e7c01
Parents:
ed4ccc7
git-author:
Alex Dehnert <adehnert@…> (03/24/10 06:34:54)
git-committer:
Alex Dehnert <adehnert@…> (03/24/10 06:34:54)
Message:

Calculate totals using annotate, not aggregate

For reports like "all the accounts ever", this can
increase performance by a factor of about three
and reduce the number of database queries by a
factor of about a hundred (aka the number of rows
in the table produced).

It is substantially more complicated, though.
The original code is in a "slow = False; if slow:"
block. In theory, it'd be good to keep both codepaths
working and test them against each other.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • remit/finance_core/views.py

    red4ccc7 r3f1e074  
    1515    line_items = finance_core.models.LineItem.objects.all()
    1616    term_name = 'All'
     17    term_primary_Q = Q()
    1718    if 'term' in request.REQUEST:
    1819        term_obj = get_object_or_404(finance_core.models.BudgetTerm, slug=request.REQUEST['term'])
    1920        term_name = term_obj.name
    2021        line_items = line_items.filter(budget_term=term_obj)
     22        term_primary_Q = Q(lineitem__budget_term=term_obj)
    2123    if 'area' in request.REQUEST:
    2224        base_area_obj = get_object_or_404(finance_core.models.BudgetArea, pk=request.REQUEST['area'])
     
    2931    primary_name = 'Budget Areas'
    3032    primary_axis = [
    31         (area.indented_name(base_area_depth), Q(budget_area=area), ) for area in base_area_obj.get_descendants()
     33        (area.pk, area.indented_name(base_area_depth), Q(budget_area=area), ) for area in base_area_obj.get_descendants()
    3234    ]
     35    primary_axis_objs = base_area_obj.get_descendants()
    3336    secondary_name = 'Layers'
    34     secondary_axis = [ (finance_core.models.layer_name(layer), Q(layer=finance_core.models.layer_num(layer)), ) for layer in finance_core.models.layers ]
     37    secondary_axis = [
     38        (
     39            finance_core.models.layer_name(layer),
     40            Q(layer=finance_core.models.layer_num(layer)),
     41            Q(lineitem__layer=finance_core.models.layer_num(layer)),
     42        )
     43        for layer in finance_core.models.layers
     44    ]
    3545
    36     primary_axis.append(('Total', Q(), ))
    37     secondary_axis.append(('Total', Q(), ))
     46    secondary_axis.append(('Total', Q(), Q()))
    3847
    39     primary_labels = [ primary[0] for primary in primary_axis ]
     48    primary_labels = [ ]
     49    arcprimary = {}
     50    table = []
     51    zero = Decimal('0.00')
     52    for num, (pk, label, qobj, ) in enumerate(primary_axis):
     53        primary_labels.append(label)
     54        arcprimary[pk] = num
     55        table.append([zero]*len(secondary_axis))
     56    print arcprimary
     57
    4058    secondary_labels = [ secondary[0] for secondary in secondary_axis ]
    4159
    42     zero = Decimal('0.00')
    43     def total_amount(queryset):
    44         amount = queryset.aggregate(Sum('amount'))['amount__sum']
    45         if amount is None: return zero
    46         else: return amount
    47     table = [ # Primary axis
    48             [ # Secondary axis
    49                 total_amount(line_items.filter(primary[1], secondary[1]))
    50             for secondary in secondary_axis]
    51         for primary in primary_axis]
     60    def lineitem_total(obj):
     61        if obj.lineitem__amount__sum is None: return zero
     62        else: return obj.lineitem__amount__sum
     63    for num, (label, qobj_lineitem, qobj_primary) in enumerate(secondary_axis):
     64        secondary_results = (primary_axis_objs.filter(qobj_primary, term_primary_Q).annotate(Sum('lineitem__amount')))
     65        for cell in secondary_results:
     66            print cell, cell.pk, arcprimary[cell.pk], num, table[arcprimary[cell.pk]]
     67            table[arcprimary[cell.pk]][num] = lineitem_total(cell)
     68
     69    slow = False
     70    if slow:
     71        # This uses a simpler but probably slower method
     72        # In theory, if we grow unit tests, comparing this method with
     73        # the one above using annotate would be a good idea
     74        def total_amount(queryset):
     75            amount = queryset.aggregate(Sum('amount'))['amount__sum']
     76            if amount is None: return zero
     77            else: return amount
     78        table = [ # Primary axis
     79                [ # Secondary axis
     80                    total_amount(line_items.filter(primary[1], secondary[1]))
     81                for secondary in secondary_axis]
     82            for primary in primary_axis]
    5283
    5384    debug = False
Note: See TracChangeset for help on using the changeset viewer.