如何使用基于 class 的视图按 Django 中相关字段的总和进行排序?

How to sort by the sum of a related field in Django using class based views?

如果我有一个如下所示的 Agent 模型:

class Agent(models.Model):
    name = models.CharField(max_length=100)

和如下所示的相关模型:

class Deal(models.Model):
    agent = models.ForeignKey(Agent, on_delete=models.CASCADE)
    price = models.IntegerField()

和一个看起来像这样的视图:

from django.views.generic import ListView

class AgentListView(ListView):    
    model = Agent

我知道我可以在 queryset 中调整代理的排序顺序,我什至知道如何按照代理的交易数量对代理进行排序:

queryset = Agent.objects.all().annotate(uc_count=Count('deal')).order_by('-uc_count')

但是,我不知道如何根据每个代理商的交易价格总和对交易进行排序。

假设您已经知道如何根据这些注释进行注释和排序,那么您已经完成了 90%。您只需要使用 Sum 聚合并向后遵循关系。

Django docs give this example:

Author.objects.annotate(total_pages=Sum('book__pages'))

您应该可以做类似的事情:

queryset = Agent.objects.all().annotate(deal_total=Sum('deal__price')).order_by('-deal_total')

我的敏锐感觉告诉我您可能需要向 Sum 聚合中添加一个 distinct=True,但如果不进行测试我不确定。

根据 Greg Kaleka 的答案和您在他的回复中提出的问题,这可能是您正在寻找的解决方案:

from django.db.models import Case, IntegerField, When

queryset = Agent.objects.all().annotate(
    deal_total=Sum('deal__price'),
    o=Case(
        When(deal_total__isnull=True, then=0), 
        default=1, 
        output_field=IntegerField()
    )
).order_by('-o', '-deal_total')

解释:

发生的事情是 deal_total 字段将 deals 对象的 price 相加,但如果 Agent 没有 deals首先,price 的总和是 NoneWhen 对象能够将 0 的值分配给 deal_total,否则该对象将被赋予 None

的值