我有以下型号:
class Book(models.Model):
name = models.CharField(max_length=255)
published = models.DateField()
items_sold = models.IntegerField()
现在,我想按发布日期对所有图书进行分组,我希望SUM
已售出的项目(items_sold
)。另外,我想在输出中添加所有names
的列表。所以我的预期输出看起来像这样:
[{'date': datetime.date(2015, 12, 14), 'total_sold': 5000, 'names': ['Book A', 'Book B']},
{'date': datetime.date(2016, 11, 4), 'total_sold': 10000, 'names': ['Book C']}, ... ]
我尝试使用annotate
解决此问题:
Book.objects.values('date').annotate(total_sold=Sum('items_sold'))
但我不知道如何在结果中获取名称列表。这里有annotate
正确的方法吗?有谁知道如何解决这个问题?
感谢Todor的评论,我发现使用自定义聚合的部分解决方案:
class Concat(models.Aggregate):
"""
Using SQLite `group_concat` function
"""
function = 'group_concat'
template = '%(function)s(%(field)s, "%(separator)s")'
现在我有了这个问题:
Book.objects.values('date').annotate(total_sold=Sum('items_sold'), names=Concat('names', separator=',')
> [{'date': datetime.date(2016, 1, 5), 'total_sold': 5000, 'names': 'Book A, Book B'}, ...,]
现在的问题是书名连接到字符串names
。我可以定义一个分隔符,但我不知道如何将names
转换为列表。
我可以稍后使用split
(names.split(separator)
)执行此操作,但我认为这不够节省,因为我的分隔符也可能是书名的一部分。
有什么建议吗?
答案 0 :(得分:1)
没有提到您正在使用的数据库。但Django 1.9提供了某些postgres specific aggregate functions,例如ArrayAgg
这将非常有用:
from django.contrib.postgres.aggregates import ArrayAgg
Book.objects.values('date').annotate(total_sold=Sum('items_sold'), names=ArrayAgg('name'))
并且,这将聚合所有名称并将它们放入列表中。