如何使用基于 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
字段将 deal
s 对象的 price
相加,但如果 Agent
没有 deal
s首先,price
的总和是 None
。 When
对象能够将 0
的值分配给 deal_total
,否则该对象将被赋予 None
的值
如果我有一个如下所示的 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
字段将 deal
s 对象的 price
相加,但如果 Agent
没有 deal
s首先,price
的总和是 None
。 When
对象能够将 0
的值分配给 deal_total
,否则该对象将被赋予 None