简体   繁体   English

Django字段中的项目计数

[英]Django Count of Items in a Field

models.py 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()

I want to do a query to return a count of each unique Category in the Result table, for a given Event. 我想进行查询以返回给定事件的Result表中每个唯一Category的计数。

What I'm doing now is something like: 我现在正在做的是:

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

Is there a better way, perhaps by query instead of python. 有没有更好的方法,可能是通过查询而不是python。

You can use annotate() with values() . 您可以将annotate()values() This approach is shown in the docs for values() . 这种方法显示在values()的文档中。 To get the count for each category name, you could do: 要获取每个类别名称的计数,您可以执行以下操作:

from django.db.models import Count

categories = Result.objects.filter(
    event=myevent,
).order_by('category').values(
    'category__name'
).annotate(count=Count('category__name'))

This will return a list of dictionaries with keys category__name and count , for example: 这将返回一个字典列表,其中包含键category__namecount ,例如:

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

You could convert this to a single dictionary by using a dictionary comprehension: 您可以使用字典理解将其转换为单个字典:

counts_by_category = {d['category__name']: d['count'] for f in categories}

Use annotate : 使用annotate

from django.db.models import Count

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

There is collections.Counter in python standard library: python标准库中有collections.Counter

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

Now c is a dict-like object where keys are Category instances, and values are counts. 现在c是一个类似dict的对象,其中键是Category实例,值是计数。

This option is not suitable for large datasets though, since it doesn't use database features. 但是,此选项不适用于大型数据集,因为它不使用数据库功能。 So if you have a lot of data, approaches that use values, annotate and Count are more suitable. 因此,如果您有大量数据,那么使用值,注释和计数的方法更合适。

select_related is used here in order to eliminate database hit for every result. 这里使用select_related以消除每个结果的数据库命中。 Basically it makes 1 query with join and generates python objects for categories. 基本上,它使用join进行1次查询,并为类别生成python对象。



It turns out, that ManyToManyField keeps track of unique records only, so below answer is incorrect. 事实证明,ManyToManyField仅跟踪唯一记录,因此下面的答案是不正确的。

Your Event and Category models expose many-to-many connection through Result model. 您的事件和类别模型通过结果模型公开多对多连接。

You can express it using through in Django (note categories 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')

In your code, for given event you could query like this: 在您的代码中,对于给定的事件,您可以像这样查询:

event.categories.count()

Taking Alasdair note into account: 考虑到Alasdair的注意事项:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM