I query a model,
Members.objects.all()
and it returns say
Eric, Salesman, X-Shop
Freddie, Manager, X2-Shop
Teddy, Salesman, X2-Shop
Sean, Manager, X2-Shop
What i want is, to know the best Django way to fire a group_by query to my db, as like,
Members.objects.all().group_by('designation')
Which doesn't work of course. I know we can do some tricks on "django/db/models/query.py", but i am just curious to know how to do it without patching.
You need to do custom SQL as exemplified in this snippet:
Custom SQL via subquery
Or in a custom manager as shown in the online Django docs:
Adding extra Manager methods
You can also use the
regroup
template tag to group by attributes. From the docs:Looks like this:
It also works on
QuerySet
s I believe.source: https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#regroup
There is module that 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:
'book/books.html'
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:
NOTE:
ArrayAgg
is a Postgres specific function, available from Django 1.9 onwards: https://docs.djangoproject.com/en/1.10/ref/contrib/postgres/aggregates/#arrayaggfirst you need to import Sum then ..
An easy solution, but not in a proper way is to use RAW-SQL:
http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql
Another solution is to use the group_by property:
You can now iterate over the results variable to retrieve your results. Note that group_by is not documented and may be changed in future version of Django.
And... why do you want to use group_by? If you don't use aggregation, you can use order_by to achieve an alike result.
Django does not support free group by queries. I learned it in the very bad way. ORM is not designed to support stuff like what you want to do, without using custom SQL. You are limited to:
cr.execute
sentences (and a hand-made parsing of the result)..annotate()
(the group by sentences are performed in the child model for .annotate(), in examples like aggregating lines_count=Count('lines'))).Over a queryset
qs
you can callqs.query.group_by = ['field1', 'field2', ...]
but it is risky if you don't know what query are you editing and have no guarantee that it will work and not break internals of the QuerySet object. Besides, it is an internal (undocumented) API you should not access directly without risking the code not being anymore compatible with future Django versions.