У меня есть следующий вид:
from itertools import chain, groupby
from django.db.models.aggregates import Sum
from django.shortcuts import render_to_response, get_object_or_404
from django.template.context import RequestContext
import operator
from accounts.models import GeneralLedger, Account, Journal
from receivables.models import Item as ReceivableItem
from payables.models import Item as PayableItem
ACCOUNT_TYPES = {
'INC':1,
'COGS':2,
'EXP':3,
'NCA':4,
'CA':5,
'NCL':6,
'CL':7,
'EQ':8,
}
def income_statement(request):
""" General income statement"""
# Get a aggregated total per account type
debit_ledger = GeneralLedger.objects.values('debit_account','amount')
credit_ledger = GeneralLedger.objects.values('credit_account','amount')
debit_journal = Journal.objects.values('debit_account','amount')
credit_journal = Journal.objects.values('credit_account','amount')
debit_receivables = ReceivableItem.objects.values('debit_account','amount')
credit_receivables = ReceivableItem.objects.values('credit_account','amount')
debit_payables = PayableItem.objects.values('debit_account','amount')
credit_payables = PayableItem.objects.values('credit_account','amount')
general_ledger = chain(debit_ledger, credit_ledger, debit_journal, credit_journal, debit_receivables,
credit_receivables, debit_payables, credit_payables)
generalledger = list(general_ledger)
gross_total = 0
net_profit = 0
# For each general ledger item
# get the account name (because value query set only returns ID)
# get the account type so we're able to set the order for the template display
for e in generalledger:
if "debit_account" in e:
account_detail = get_object_or_404(Account, pk=e["debit_account"])
e['account'] = e['debit_account']
e['amount'] = -e['amount']
if "credit_account" in e:
account_detail = get_object_or_404(Account, pk=e["credit_account"])
e['account'] = e['credit_account']
e["account_name"] = account_detail.name
e["account_type"] = account_detail.type
if account_detail.type == 'INC':
e["order"] = ACCOUNT_TYPES['INC']
# add to the gross total
gross_total += e['amount']
elif account_detail.type == 'COGS':
# subtract from the gross total
gross_total -= e['amount']
e["order"] = ACCOUNT_TYPES['COGS']
elif account_detail.type == 'EXP':
# net profit is gross total minus the expenses
net_profit = gross_total - e['amount']
e["order"] = ACCOUNT_TYPES['EXP']
generalledger = sorted(generalledger, key=operator.itemgetter('account'))
groups = []
uniquekeys = []
for k, g in groupby(generalledger, operator.itemgetter('account')):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
for group in groups:
group_total = 0
for subgroup in group:
group_total += subgroup['amount']
subgroup['total'] = group_total
context_dict = {
'GeneralLedger': groups,
'Gross': gross_total,
'Net': net_profit,
}
return render_to_response('accounts/income-statement.html', context_dict, RequestContext(request))
Это работает, однако я не думаю, что это очень эффективно, так как на каждой итерации он вызывает базу данных. Я пытался использовать
objects.only (...) вместо objects.values (...), однако тогда я не могу добавить нужные мне элементы. Есть ли более эффективный способ сделать это?