Xen_mar
Xen_mar

Reputation: 9682

Caching model properties in Django

In my Django app, I have a very repetitive query calling for item in self.schemaitem_set.all() very often. I feel this code is vastly inefficient. I am looking for a way to cash the query. Do you guys know how I could make the code below better?

@property
def gross(self):
    gross_sum = Decimal('0')
    for item in self.schemaitem_set.all():
        gross_sum += item.gross
    return gross_sum

@property
def net(self):
    net_sum = Decimal('0')
    for item in self.schemaitem_set.all():
        net_sum += item.net
    return net_sum

@property
def deposit(self):
    deposit_sum = Decimal('0')
    for item in self.schemaitem_set.all():
        deposit_sum += item.deposit
    return deposit_sum

@property
def service_cost(self):
    service_cost = Decimal('0')
    if self.net > Decimal('150'):
        pass
    else:
        service_cost += Decimal('9.99')
    return service_cost

@property
def service_cost_vat(self):
    service_cost_vat = Decimal('0')
    if self.net > Decimal('150'):
        pass
    else:
        service_cost_vat += Decimal(f'{9.99*0,19}')
    return service_cost_vat

@property
def vat(self):
    vat = Decimal('0')
    for item in self.schemaitem_set.all():
        vat += item.vat
    return vat

Upvotes: 1

Views: 226

Answers (1)

Lord Elrond
Lord Elrond

Reputation: 16032

You can use aggregates for this:

from django.db.models import Sum

@property
def gross(self):  
    return self.schemaitem_set.all().aggregate(Sum('gross'))

Now, the computation is done at the database level, and only the sum of the columns is queried.

If you constantly perform these methods together on the same template, you can reduce them to one query:

def get_aggregate_data(self):
   qs = self.schematem_set.all(
   ).aggregate(Sum('gross'), Sum('net'), Sum('deposit'), Sum('vat')) 
   qs.service_cost, qs.service_cost_vat = (Decimal('9.99'), Decimal(f'{9.99*0,19}')) if qs.net > Decimal('150') else (Decimal('0'), Decimal('0'))
   return qs

You can access the aggregates in your template like this:

{{ qs.price__gross }}
{{ qs.price__net }}
{{ qs.service_cost }}

Upvotes: 1

Related Questions