Django самый эффективный способ подсчета одинаковых значений полей в запросе - PullRequest
43 голосов
/ 31 августа 2010

Скажем, если у меня есть модель, которая имеет много полей, но я забочусь только о поле char.Допустим, что charfield может быть чем угодно, поэтому я не знаю возможных значений, но я знаю, что значения часто перекрываются.Таким образом, у меня может быть 20 объектов с «abc» и 10 объектов с «xyz», или у меня может быть 50 объектов с «def» и 80 с «stu», и у меня 40000 без перекрытия, которые мне действительно безразличны.

Как эффективно считать объекты?Я хотел бы получить что-то вроде:

{'abc': 20, 'xyz': 10, 'other': 10000}

или что-то подобное, без созданиятонна вызовов 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'))

но ...

вот что такое группы:

{"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 ]

74 голосов
/ 31 августа 2010

Вы хотите что-то похожее на "count ... group by". Вы можете сделать это с помощью функций агрегации ORM django:

from django.db.models import Count

fieldname = 'myCharField'
MyModel.objects.values(fieldname)
    .order_by(fieldname)
    .annotate(the_count=Count(fieldname))

Предыдущие вопросы по этой теме:

16 голосов
/ 31 августа 2010

Это называется агрегацией, и Django поддерживает его напрямую .

. Точный вывод можно получить, отфильтровав значения, которые вы хотите посчитать, получив список значений и посчитав их, все в одном наборе вызовов базы данных:

from django.db.models import Count
MyModel.objects.filter(myfield__in=('abc', 'xyz')).\
        values('myfield').annotate(Count('myfield'))
7 голосов
/ 31 августа 2010

Для этого можно использовать Count агрегацию Django в наборе запросов.Как то так:

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)
1 голос
/ 17 марта 2018

Если значение вашего поля не всегда гарантировано соответствует конкретному случаю, может быть полезно преобразовать его до выполнения подсчета, т. Е. Чтобы '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')
...