Django Queryset的高效使用
我有以下看法:Django Queryset的高效使用,django,django-views,django-queryset,Django,Django Views,Django Queryset,我有以下看法: 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
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(…),但是我无法向其中添加所需的项。有没有更有效的方法来实现这一点?好吧,可以对其进行大量重构,并将其缩减到现在的一小部分,但这不是问题的关键 消除每次迭代的查询确实是改进这一点的最简单的方法。您应该只在查询中包含相关的account detail字段,而不是在每次迭代中单独查询它们
debit_ledger = GeneralLedger.objects.values('debit_account', 'debit_account__name', 'debit_account__type', 'amount')
然后在结果中,您已经将其命名为e['debit\uu account\uu name']
等等,这样您就可以删除account
的每次迭代查询