【问题标题】:Django queryset top 3 of sum for each yearDjango queryset 每年总和的前 3 名
【发布时间】:2021-04-29 04:05:56
【问题描述】:

我需要从相关发票的总和中找出每年排名前 3 位的客户。因此,我通过 FK 获得了与 Invoice 相关的 2 个模型 Customer

已编辑:

class Company(models.Model):
    name = models.CharField()

class Invoice(models.Model):
    created = AutoCreatedField(_('created'))
    total = DecimalField()
    company = models.ForeignKey('users.Company', verbose_name=_('Company'),
                            on_delete=models.DO_NOTHING, related_name='invoices',
                            null=True)

我得到的总销售额如下:

qs = Company.objects\
        .annotate(year=TruncYear('invoices__created')).values('year', 'name')\
        .annotate(total=Sum('invoices__total'))\
        .order_by('year', 'total')

但是,如果我只想每年获得前 3 名怎么办?我应该手动迭代吗:

years = [year.year for year in set(qs.values_list('year', flat=True))]

for y in years:
     new_qs = qs.filter(year__year=y).order_by('-total')[:3]
     my_top.append(new_qs)

这不是一次性获得有限查询集的方法吗?

【问题讨论】:

  • 您的模型看起来如何?将相关模型添加到 OP
  • 感谢您的关注,但在这里,它不会添加任何相关信息。你有一个与 B 相关的 A,通过 FK,就是这样。
  • 你在使用带有window函数的数据库吗?
  • @Marco 是的,最近的 PG:这很有趣。它需要原始 sql。
  • 您的请求很难在原始 sql 中实现。你想在 ORM 中做吗?对于这种情况,您可以在 Django 中使用原始 sql (docs.djangoproject.com/en/3.1/topics/db/sql)

标签: python django django-queryset


【解决方案1】:

根据几个答案,除了您建议的方法之外别无他法。请参阅Clean way to use postgresql window functions in django ORM?Django filtering on Window functions

尽管如此,我仍然想分享窗口函数以在每一行上添加一个排名。你可以在迭代过程中做任何你想做的事情:

from django.db.models.functions import TruncYear, Rank
from django.db.models import F, Window, Q, Sum

Company.objects\
    .annotate(year=TruncYear('invoices__created')).values('year', 'name')\
    .annotate(total=Sum('invoices__total'))\
    .annotate(
        rank=Window(
            expression=Rank(),
            order_by=Sum('invoices__total'),
            partition_by=[F('year')]
        )
    )

这将导致:

{'name': 'Company A', 'year': datetime.date(2019, 1, 1), 'total': Decimal('3000.00'), 'rank': 1}
{'name': 'Company B', 'year': datetime.date(2019, 1, 1), 'total': Decimal('6000.00'), 'rank': 2}
{'name': 'Company C', 'year': datetime.date(2019, 1, 1), 'total': Decimal('9000.00'), 'rank': 3}
{'name': 'Company D', 'year': datetime.date(2019, 1, 1), 'total': Decimal('12000.00'), 'rank': 4}
{'name': 'Company A', 'year': datetime.date(2020, 1, 1), 'total': Decimal('2000.00'), 'rank': 1}
{'name': 'Company B', 'year': datetime.date(2020, 1, 1), 'total': Decimal('4000.00'), 'rank': 2}
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-04
    • 1970-01-01
    • 2018-10-09
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 2021-04-13
    相关资源
    最近更新 更多