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。
答案 0 :(得分:8)
您可以将j % p
与annotate()
一起使用。这种方法显示在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'))