I query a model:
Members.objects.all()
And it returns:
Eric, Salesman, X-Shop
Freddie, Manager, X2-Shop
Teddy, Salesman, X2
The following module allows you to group Django models and still work with a QuerySet in the result: https://github.com/kako-nawao/django-group-by
For example:
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)
'book/books.html'
{% for book in object_list %}
-
{{ book.title }}
{{ book.author.last_name }}, {{ book.author.first_name }}
{{ book.shop_count }}
{{ book.price_avg }}
{% endfor %}
The difference to the annotate
/aggregate
basic Django queries is the use of the attributes of a related field, e.g. book.author.last_name
.
If you need the PKs of the instances that have been grouped together, add the following annotation:
.annotate(pks=ArrayAgg('id'))
NOTE: ArrayAgg
is a Postgres specific function, available from Django 1.9 onwards: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/aggregates/#arrayagg