在Django中获取查询集中对象的数量

119

我如何在数据库中添加一个用于计数对象的字段。我有以下模型:

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

class Contest(models.Model);
    name = models.CharField()

class Votes(models.Model):
    user = models.ForeignKey(User)
    item = models.ForeignKey(Item)
    contest = models.ForeignKey(Contest)
    comment = models.TextField()

为了查找 contestA 的投票数,我在我的视图中使用了以下查询

current_vote = Item.objects.filter(votes__contest=contestA)

这将返回一个包含每个投票的查询集,但我想要获取每个条目的投票数量,有人知道我该如何做吗?谢谢

4个回答

198

要获取特定项目的投票数量,您可以使用:

vote_count = Item.objects.filter(votes__contest=contestA).count()
如果您想要了解特定竞赛投票的分布情况,我会执行以下操作:
contest = Contest.objects.get(pk=contest_id)
votes   = contest.votes_set.select_related()

vote_counts = {}

for vote in votes:
  if not vote_counts.has_key(vote.item.id):
    vote_counts[vote.item.id] = {
      'item': vote.item,
      'count': 0
    }

  vote_counts[vote.item.id]['count'] += 1

这将创建一个将项目映射到投票数的字典。虽然这不是唯一的方法,但这种方法对数据库的压力较小,因此运行相对较快。


1
对于任何感兴趣的人 - has_key 在 Python 3 中已被移除:您可以更新它以使用 in 运算符代替。示例:if vote.item.id not in vote_counts: vote_counts[vote.item.id] = { 'item': vote.item, 'count': 0 } - RealScatman

26

另一种方法是使用聚合功能。您应该能够使用单个查询实现类似的结果。例如:

from django.db.models import Count

Item.objects.values("contest").annotate(Count("id"))

我没有测试过这个特定的查询,但是这应该会将每个contests值的项目计数作为字典输出。


1
这对我来说仍然很困惑。如果在一个queryset上进行注释,你计算的是每个对象所属的id数量,显然是1。那么这有什么用呢? - AlxVallejo
是的,如果您在Contest模型上计算“contest”,那么情况就是这样。但是,在这种情况下,我们正在对具有唯一竞赛的“Item”进行聚合。 - salomonvh
如果两个对象的计数相同,然后我们必须根据其他条件对它们进行排序。那么该怎么做呢? - Tarun
@Tarun,您可以在注释中添加值,但请确保不要尝试添加在注释期间被聚合的项目。由于它返回一个查询集,因此所有通常的排序函数仍然适用.order_by('some_value') - salomonvh

2
使用related_name来统计特定竞赛的投票数。
class Item(models.Model):
    name = models.CharField()

class Contest(models.Model);
    name = models.CharField()

class Votes(models.Model):
    user = models.ForeignKey(User)
    item = models.ForeignKey(Item)
    contest = models.ForeignKey(Contest, related_name="contest_votes")
    comment = models.TextField()

>>> comments = Contest.objects.get(id=contest_id).contest_votes.count()

0

您可以使用len()来获取contestA的投票数

current_vote = len(Item.objects.filter(votes__contest=contestA))

实际上,len()select_for_update() 一起使用,如下所示:
current_vote = len(Item.objects.select_for_update().filter(votes__contest=contestA))

因为select_for_update()与下面展示的count()不兼容:

current_vote = Item.objects.select_for_update().filter(votes__contest=contestA).count()

您可以查看我的回答,其中解释了使用select_for_update()count()len()的相关内容。


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