django - самый эффективный способ подсчета одинаковых значений полей в запросе

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

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

{'abc': 20, 'xyz': 10, 'другое': 10,000}

или что-то в этом роде, без тонны вызовов 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"}

(Я просто заполнил изнаночные фиктивные значения)

то, что я хочу, это

{'waka': 4, 'mora': 5, 'lora': 1}

Надеюсь, кто-нибудь увидит это изменение ...

РЕДАКТИРОВАТЬ 2:

Очевидно, моя база данных (BigTable) не поддерживает агрегированные функции Django, и именно поэтому у меня были все проблемы.


person DantheMan    schedule 31.08.2010    source источник


Ответы (4)


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

from django.db.models import Count

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

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

person beerbajay    schedule 31.08.2010
comment
на самом деле у меня было это: groups = Action.objects.filter (author = author) .values ​​('purl'). annotate (count = Count ('purl')) a = [each for each in groups] but a is just равно лишь набору из них: {purl: wakawaka} без клавиши счета для словаря. - person DantheMan; 01.09.2010
comment
Я отредактировал ответ, чтобы учесть это, но на всякий случай он не будет одобрен: если вы получаете несколько результатов, которые не выглядят агрегированными: убедитесь, что вы упорядочиваете набор запросов по полю, по которому хотите сгруппировать. - person Darian Moody; 02.02.2017
comment
Спасибо за этот ответ. Это ЕДИНСТВЕННЫЙ ответ, в котором перед аннотацией упоминается order_by, который НЕОБХОДИМ для работы. - person killerbarney; 15.11.2017
comment
Почему требуется order_by? - person Jarad; 30.07.2020

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

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

from django.db.models import Count
MyModel.objects.filter(myfield__in=('abc', 'xyz')).\
        values('myfield').annotate(Count('myfield'))
person Daniel Roseman    schedule 31.08.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)
person Manoj Govindan    schedule 31.08.2010

Если значение вашего поля не всегда гарантированно относится к конкретному случаю, может быть полезно преобразовать его перед выполнением подсчета, то есть так, что «яблоко» и «яблоко» будут рассматриваться как одно и то же.

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')
person alstr    schedule 17.03.2018