Django查询多个求和值

时间:2017-02-20 13:09:53

标签: django

我有两张桌子:

票务表

id  paid_with_tax  location
1   5              A
2   6              B
3   7              B

TicketAdjustment Table

id  ticket_id  value_with_tax
1   1          2
2   1          1
3   1          2
4   1          3
5   2          5

我使用的查询:

Ticket.objects.all().annotate(
   paid_amount=Sum(
        F('paid_with_tax') +
        Coalesce(F('ticketadjustment__value_with_tax'), 0)
    )
).values(
    'paid_amount', 'location'
).annotate(
    Count('id)
)

查询将返回以下内容:

[
 {
    id__count: 6,
    paid_amount__sum: 28,
    location: A
 },
 {
    id__count: 2,
    paid_amount__sum: 18,
    location: B
 },
]

但上述内容不正确,因为Ticket表id = 1值与TicketAdjustment Table值重复。

如何在添加之前获取查询以对TicketAdjustment Table值求和。

一些限制: - 理想情况下,调用的顺序保持不变,因为我有一个函数可以返回要进行过滤的查询集

最终结果应该如下:

[
 {
    id__count: 1,
    paid_amount__sum: 13,
    location: A
 },
 {
    id__count: 2,
    paid_amount__sum: 18,
    location: B
 },
]

models.py:

class Ticket(models.Model):
    paid_with_tax = models.DecimalField(max_digits=6, decimal_places=4)
    location = models.ForeignKey(Location)


class TicketAdjustment(models.Model):
    value_with_tax = models.DecimalField(max_digits=6, decimal_places=4)
    ticket = models.ForeignKey(Ticket)

1 个答案:

答案 0 :(得分:-1)

据我所知,即使使用原始SQL查询也无法进行此聚合。因为使用TicketAdjustment加入Ticket的结果如下:

enter image description here

因此,我们不能将与value_with_tax某个故障单相关的所有paid_with_tax与按地点分组。

我找不到在一个sql查询中执行此操作的解决方案。但我已经找到了如何在两个查询中执行此操作:

tickets = Ticket.objects.values(
    'location',
).annotate(
    count=Count('id', distinct=True),
    paid_amount=Sum('paid_with_tax')
)
# <QuerySet [
#     {'paid_amount': 5, 'count': 1, 'location': 'A'},
#     {'paid_amount': 13, 'count': 2, 'location': 'B'}
# ]>

adjustments = TicketAdjustment.objects.annotate(
    location=F('ticket__location'))
.values(
    'location',
).annotate(
    paid_amount=Sum('value_with_tax')
)
# <QuerySet [
#     {'paid_amount': 5, 'location': 'B'},
#     {'paid_amount': 8, 'location': 'A'}
# ]>

def find_paid_amount_for_list_and_location(l, location):
    for item in l:
        if item['location'] == location:
            return item['paid_amount'] or 0

for obj in tickets:
    paid = find_paid_amount_for_list_and_location(adjustments, obj['location'])
    obj['paid_amount'] += paid

tickets
# [
#     {'location': 'A', 'paid_amount': 13, 'count': 1},
#     {'location': 'B', 'paid_amount': 18, 'count': 2}
# ]

但这不是超级高效的解决方案,我认为您应该为位置创建新表并且只有FK到该表?在这种情况下,您将能够在db端的一个查询中执行这些计算。