我有2个这样的模型:
class Client(models.Model):
// some fields
class Transaction(models.Model):
client = models.ForeignKey(Client)
created = models.DateTimeField(auto_now_add=True)
amount = DecimalField(max_digits=9, decimal_places=2)
仅当Transaction
低于提供的created
参数时,我想编写一个查询,为每个客户添加最后创建的date
金额。
例如,如果我有一个像这样的数据集,并且提供的date
是01/20:
Client1:
- Transaction 1, created on 01/15, 5€
- Transaction 2, created on 01/16, 6€
- Transaction 3, created on 01/22, 7€
Client2:
- Transaction 4, created on 01/18, 8€
- Transaction 5, created on 01/19, 9€
- Transaction 6, created on 01/21, 10€
Client3:
- Transaction 7, created on 01/21, 11€
然后,查询应返回15
(交易2和交易5中的6€+ 9€)。
从性能的角度来看,我的目的是避免对N个客户端进行N个查询。
当前,我在选择正确的Transaction
对象时遇到麻烦。
也许我可以从以下开始:
Transaction.objects.filter(created__lt=date).select_related('client')
。
但后来,我不知道如何仅选择每个客户端的最新版本。
答案 0 :(得分:2)
看看aggregation上Django的文档,Sum,SubQuery expressions和QuerySet.values()的用法。通过这些,我们可以通过ORM构建单个查询以了解您要执行的操作,从而允许数据库完成所有工作:
from django.db.models import Sum, Subquery, OuterRef
from django.utils import timezone
from . import models
# first, start with the client list, rather than the transaction list
aggregation = models.Client.objects.aggregate(
# aggregate the sum of our per client sub queries
result=Sum(
Subquery(
models.Transaction.objects.filter(
# filter transactions by outer query's client pk
client=OuterRef('pk'),
created__lt=timezone.datetime(2018, 1, 20),
)
# order descending so the transaction we're after is first in the list
.order_by('-created')
# use QuerySet.values() to grab just amount and slice the queryset
# to limit the subquery result to a single transaction for each client
.values('amount')[:1]
)
)
)
# aggregation == {'result': Decimal('15.00')}
答案 1 :(得分:0)
使用以下方法应该可以解决使用Django latest QuerySet方法的问题
total = 0
for client in clients
try:
total += Transactions.filter(client = client).filter(created__lt = date).latest('created').amount
except DoesNotExist:
pass