Django字段中的项目计数

时间:2016-09-15 14:24:58

标签: python django django-models

models.py

class Event(models.Model):
    name = models.CharField(max_length=20, unique=True)
    distance = models.IntegerField()
    date = models.DateField()

class Category(models.Model):
    name = models.CharField(max_length=20, unique=True)
    description = models.CharField(max_length=20, unique=True)
    isnew = models.BooleanField(default=False)

class Result(models.Model):
    event = models.ForeignKey(Event)
    category = models.ForeignKey(Category)
    score = models.IntegerField()

对于给定的事件,我想进行查询以返回Result表中每个唯一Category的计数。

我现在所做的是:

results = Result.objects.filter(event=myevent)
categorycountdict = {}
for r in results:
    if r.category in categorycountdict:
        categorycountdict[r.category] += 1
    else:
        categorycountdict[r.category] = 1

是否有更好的方法,可能是通过查询而不是python。

3 个答案:

答案 0 :(得分:8)

您可以将j % pannotate()一起使用。这种方法显示在values()的文档中。要获取每个类别名称的计数,您可以执行以下操作:

values()

这将返回包含键from django.db.models import Count categories = Result.objects.filter( event=myevent, ).order_by('category').values( 'category__name' ).annotate(count=Count('category__name')) category__name的词典列表,例如:

count

您可以使用词典理解将其转换为单个词典:

[{'count': 3, 'category__name': u'category1'}, {'count': 1, 'category__name': u'category2'}]

答案 1 :(得分:0)

使用annotate

from django.db.models import Count

Results.objects.filter(event=some_event).annotate(Count('category'), distinct=True)

答案 2 :(得分:0)

python标准库中有collections.Counter

results = Result.objects.filter(event=myevent).select_related('category')
c = Counter(r.category for r in results)

现在c是一个类似dict的对象,其中键是Category实例,值是计数。

此选项不适用于大型数据集,因为它不使用数据库功能。因此,如果您有大量数据,那么使用值,注释和计数的方法更合适。

此处使用

select_related以消除每个结果的数据库命中。基本上它使用join进行1次查询并为类别生成python对象。

事实证明,ManyToManyField仅跟踪唯一记录,因此下面的答案不正确。

您的事件和类别模型通过结果模型公开多对多连接。

您可以在Django中使用through表达它(注意类别ManyToManyField):

class Event(models.Model):
    name = models.CharField(max_length=20, unique=True)
    distance = models.IntegerField()
    date = models.DateField()
    categories = models.ManyToManyField(Category, through='Result', related_name='events')

在您的代码中,对于给定的事件,您可以这样查询:

event.categories.count()

考虑到Alasdair的注意事项:

event.categories.values('pk').annotate(count=Count('pk'))