Существует модуль, который позволяет группировать модели Django и по-прежнему работать с QuerySet в результате: https://github.com/kako-nawao/django-group-by
Например:
from django_group_by import GroupByMixin
class BookQuerySet(QuerySet, GroupByMixin):
pass
class Book(Model):
title = TextField(...)
author = ForeignKey(User, ...)
shop = ForeignKey(Shop, ...)
price = DecimalField(...)
class GroupedBookListView(PaginationMixin, ListView):
template_name = 'book/books.html'
model = Book
paginate_by = 100
def get_queryset(self):
return Book.objects.group_by('title', 'author').annotate(
shop_count=Count('shop'), price_avg=Avg('price')).order_by(
'name', 'author').distinct()
def get_context_data(self, **kwargs):
return super().get_context_data(total_count=self.get_queryset().count(), **kwargs)
книга / books.html '
<ul>
{% for book in object_list %}
<li>
<h2>{{ book.title }}</td>
<p>{{ book.author.last_name }}, {{ book.author.first_name }}</p>
<p>{{ book.shop_count }}</p>
<p>{{ book.price_avg }}</p>
</li>
{% endfor %}
</ul>
Отличие от annotate
/ aggregate
базовых запросов Django заключается в использовании атрибутов связанного поля, например, book.author.last_name
.
Если вам нужны PK экземпляров, которые были сгруппированы вместе, добавьте следующую аннотацию:
.annotate(pks=ArrayAgg('id'))
ПРИМЕЧАНИЕ: ArrayAgg
- это специальная функция Postgres, доступная с Django 1.9 и далее: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/aggregates/#arrayagg