Django中查询同一字段值的最有效方式是什么?

65
假设我有一个拥有许多字段的模型,但我只关心 charfield。假设 charfield 可以是任何值,因此我不知道可能的值,但我知道这些值经常重叠。所以我可以有 20 个带有"abc"的对象和 10 个带有"xyz"的对象或者我可以有 50 个带有"def"的对象和 80 个带有"stu"的对象,并且我有 40000 个没有重叠的对象,我真的不在乎这些。
如何高效地计算这些对象?我希望返回的结果类似于:
{'abc': 20, 'xyz': 10, 'other': 10,000}
或者类似于这样,而不产生大量的 SQL 调用。
编辑:
我不知道是否有人会看到这个,因为我编辑得有点晚了,但是...
我有这个模型:
class Action(models.Model): author = models.CharField(max_length=255) purl = models.CharField(max_length=255, null=True)
根据答案,我已经做到了这一点:
groups = Action.objects.filter(author='James').values('purl').annotate(count=Count('purl'))
但是...
这就是 groups:
{"purl": "waka"},{"purl": "waka"},{"purl": "waka"},{"purl": "waka"},{"purl": "mora"},{"purl": "mora"},{"purl": "mora"},{"purl": "mora"},{"purl": "mora"},{"purl": "lora"}
(我只是用虚拟值填充了 purl)
我想要的是
{'waka': 4, 'mora': 5, 'lora': 1}
希望有人看到这个编辑...
编辑2:
显然我的数据库(BigTable)不支持 Django 的聚合函数,这就是为什么我一直有问题的原因。
4个回答

113

实际上,我有这个:groups = Action.objects.filter(author= author).values('purl').annotate(count=Count('purl'))a = [each for each in groups]但是a只等于一堆这样的东西:{"purl": "wakawaka"}字典中没有count键。 - DantheMan
我已经编辑了答案以解决这个问题,但是以防它没有被批准:如果您收到多个看起来不聚合的结果:请确保您按照您希望分组的字段对查询集进行排序。 - Darian Moody
4
谢谢您的回答。这是唯一一个在注释之前提到 order_by 的答案,这是必要的才能使其工作。 - killerbarney
1
为什么需要使用 order_by - Jarad
@Jarad,“previous questions”中提到了它,文档的这一部分也提到了它:“在查询集的order_by()部分中提到的字段在选择输出数据时被使用,即使它们在values()调用中没有被指定。这些额外的字段用于将“相似”的结果分组在一起,它们可以使本来相同的结果行看起来是不同的。这在计数时特别明显。”因此,默认排序可能会添加混乱事物的多余字段。 - mgalgs

23

这被称为聚合,Django可以直接支持

您可以通过在一组数据库调用中过滤要计数的值,获取值列表并对其进行计数来获得精确的输出:

from django.db.models import Count
MyModel.objects.filter(myfield__in=('abc', 'xyz')).\
        values('myfield').annotate(Count('myfield'))

7

您可以使用Django的Count聚合在查询集上实现此目的。类似于以下内容:

from django.db.models import Count
queryset = MyModel.objects.all().annotate(count = Count('my_charfield'))
for each in queryset:
    print "%s: %s" % (each.my_charfield, each.count)

4

如果您的字段值不能保证始终处于特定大小写,那么在执行计数之前进行转换可能会很有用,即将“apple”和“Apple”视为相同。

from django.db.models import Count
from django.db.models.functions import Lower

MyModel.objects.annotate(lower_title=Lower('title')).values('lower_title').annotate(num=Count('lower_title')).order_by('num')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接