Django:分组并返回多个字段

问题描述 投票:0回答:1

在 Django 中,考虑以下模型类,

class Report(models.Model):
    owner = models.ForeignKey(
        to=Owner,
        on_delete=models.CASCADE,
        related_name='data',
    )
    balance = models.PositiveIntegerField()
    report_date = models.DateField()

假设这张表只有以下四项,

<QuerySet [{'owner': 1, 'balance': 100, 'report_date': datetime.date(2023, 3, 4)}, {'owner': 1, 'balance': 50, 'report_date': datetime.date(2023, 3, 9)}, {'owner': 2, 'balance': 1000, 'report_date': datetime.date(2023, 2, 2)}, {'owner': 2, 'balance': 2000, 'report_date': datetime.date(2023, 2, 22)}]>

owner
和聚合
report_date
的最小值的简单组如下,

Report.objects.values('owner').annotate(min_report_date=Min('report_date')).values('owner', 'min_report_date')

结果如下,

<QuerySet [{'owner': 1, 'min_report_date': datetime.date(2023, 3, 4)}, {'owner': 2, 'min_report_date': datetime.date(2023, 2, 2)}]>

现在我想返回对应于

balance
字段的最小值的
report_date
除了像下面这样的
owner
min_report_date
字段,

<QuerySet [{'owner': 1, 'min_report_date': datetime.date(2023, 3, 4), 'balance': 100}, {'owner': 2, 'min_report_date': datetime.date(2023, 2, 2), 'balance': 1000}]>

我的尝试是下面的 Django 查询,

Report.objects.values('owner').annotate(min_report_date=Min('report_date')).values('owner', 'min_report_date', 'balance')

但是结果失去了聚合的效果(即返回了所有行),如下所示,

 <QuerySet [{'owner': 1, 'balance': 50, 'min_report_date': datetime.date(2023, 3, 9)}, {'owner': 1, 'balance': 100, 'min_report_date': datetime.date(2023, 3, 4)}, {'owner': 2, 'balance': 2000, 'min_report_date': datetime.date(2023, 2, 22)}, {'owner': 2, 'balance': 1000, 'min_report_date': datetime.date(2023, 2, 2)}]>
django django-models group-by django-orm
1个回答
1
投票

您可以使用

Subquery
表达式[Django-doc]:

from django.db.models import OuterRef, Subquery

Owner.objects.annotate(
    min_report_balance=Subquery(
        Report.objects.filter(owner_id=OuterRef('pk'))
        .order_by('report_date')
        .values('balance')[:1]
    )
)

从该查询集中产生的

Owner
对象将具有一个额外的属性
min_report_balance
,即该所有者的“最旧”
balance
Report
,或者
None
(
NULL
) 如果没有这样的报告存在。

© www.soinside.com 2019 - 2024. All rights reserved.