2๐
The Django ORM does not support this; if you donโt want to use raw SQL then youโll need to group and join.
57๐
You can create your own Aggregate Function (doc)
from django.db.models import Aggregate
class Concat(Aggregate):
function = 'GROUP_CONCAT'
template = '%(function)s(%(distinct)s%(expressions)s)'
def __init__(self, expression, distinct=False, **extra):
super(Concat, self).__init__(
expression,
distinct='DISTINCT ' if distinct else '',
output_field=CharField(),
**extra)
and use it simply as:
query_set = Fruits.objects.values('type').annotate(count=Count('type'),
name = Concat('name')).order_by('-count')
I am using django 1.8 and mysql 4.0.3
- [Django]-Python/Django: Creating a simpler list from values_list()
- [Django]-"You called this URL via POST, but the URL doesn't end in a slash" error in Django
- [Django]-How to pass information using an HTTP redirect (in Django)
20๐
NOTICE that Django (>=1.8) provides Database functions
support.
https://docs.djangoproject.com/en/dev/ref/models/database-functions/#concat
Here is an enhanced version of Shashank Singla
from django.db.models import Aggregate, CharField
class GroupConcat(Aggregate):
function = 'GROUP_CONCAT'
template = '%(function)s(%(distinct)s%(expressions)s%(ordering)s%(separator)s)'
def __init__(self, expression, distinct=False, ordering=None, separator=',', **extra):
super(GroupConcat, self).__init__(
expression,
distinct='DISTINCT ' if distinct else '',
ordering=' ORDER BY %s' % ordering if ordering is not None else '',
separator=' SEPARATOR "%s"' % separator,
output_field=CharField(),
**extra
)
Usage:
LogModel.objects.values('level', 'info').annotate(
count=Count(1), time=GroupConcat('time', ordering='time DESC', separator=' | ')
).order_by('-time', '-count')
- [Django]-"{% extends %}" and "{% include %}" in Django Templates
- [Django]-ImportError: bad magic number in 'time': b'\x03\xf3\r\n' in Django
- [Django]-Filtering ListAPIView in django-rest-framework
9๐
Use GroupConcat
from the Django-MySQL package (
https://django-mysql.readthedocs.org/en/latest/aggregates.html#django_mysql.models.GroupConcat ) which I maintain. With it you can do it simply like:
>>> from django_mysql.models import GroupConcat
>>> Fruits.objects.annotate(
... count=Count('type'),
... name_list=GroupConcat('name'),
... ).order_by('-count').values('type', 'count', 'name_list')
[{'type': 'apple', 'count': 2, 'name_list': 'fuji,mac'},
{'type': 'orange', 'count': 1, 'name_list': 'navel'}]
- [Django]-Simple way to reset Django PostgreSQL database?
- [Django]-Why am I getting this error in Django?
- [Django]-How do I run tests for all my Django apps only?
4๐
If you are using PostgreSQL, you can use ArrayAgg
to aggregate all of the values into an array.
https://www.postgresql.org/docs/9.5/static/functions-aggregate.html
- [Django]-Enforcing password strength requirements with django.contrib.auth.views.password_change
- [Django]-Django Rest Framework Conditional Field on Serializer
- [Django]-Django Abstract User Error
3๐
If you donโt mind doing this in your template the Django template tag regroup accomplishes this
- [Django]-Django: Catching Integrity Error and showing a customized message using template
- [Django]-Django โ How to get self.id when saving a new object?
- [Django]-Should I be adding the Django migration files in the .gitignore file?
3๐
As of Django 1.8 you can use Func() expressions.
query_set = Fruits.objects.values('type').annotate(
count=Count('type'),
name=Func(F('name'), 'GROUP_BY')
).order_by('-count')
- [Django]-Django: why i can't get the tracebacks (in case of error) when i run LiveServerTestCase tests?
- [Django]-Change a Django form field to a hidden field
- [Django]-Numpy Array to base64 and back to Numpy Array โ Python
3๐
Similar Aggregate Function for PostgreSQL in case someone needs:
from django.db.models import Aggregate, CharField
class GroupConcat(Aggregate):
function = "STRING_AGG"
template = "%(function)s(%(expressions)s::text, %(separator)s%(ordering)s)"
def __init__(self, expression, ordering=None, separator=',', **extra):
super().__init__(
expression,
ordering=" ORDER BY %s" % ordering if ordering is not None else "",
separator="'%s'" % separator,
output_field=CharField(),
**extra
)
queryset = Fruits.objects.values('type').annotate(
count=Count('type'),
name=GroupConcat('name')
).order_by('-count')
- [Django]-Django-object-permissions Vs django-guardian Vs django-authority
- [Django]-How to query as GROUP BY in Django?
- [Django]-Django-Rest-Framework 3.0 Field name '<field>' is not valid for model `ModelBase`
1๐
Not supported by Django ORM, but you can build your own aggregator.
Itโs actually pretty straightforward, here is a link to a how-to that does just that, with GROUP_CONCAT
for SQLite: http://harkablog.com/inside-the-django-orm-aggregates.html
Note however, that it might be necessary to handle different SQL dialects separately. For example, the SQLite docs say about group_concat
:
The order of the concatenated elements is arbitrary
While MySQL allows you to specify the order.
I guess that may be a reason why GROUP_CONCAT
itโs not implemented in Django at the moment.
- [Django]-How Can You Create an Admin User with Factory_Boy?
- [Django]-How to update() a single model instance retrieved by get() on Django ORM?
- [Django]-How do I include related model fields using Django Rest Framework?
1๐
To complete the answer of @WeizhongTu, Notice that you can not use the keyword SEPARATOR with SQLITE. In cases where you are using MySQL and SQLite for your tests, you can write :
class GroupConcat(Aggregate):
function = 'GROUP_CONCAT'
separator = ','
def __init__(self, expression, distinct=False, ordering=None, **extra):
super(GroupConcat, self).__init__(expression,
distinct='DISTINCT ' if distinct else '',
ordering=' ORDER BY %s' % ordering if ordering is not None else '',
output_field=CharField(),
**extra)
def as_mysql(self, compiler, connection, separator=separator):
return super().as_sql(compiler,
connection,
template='%(function)s(%(distinct)s%(expressions)s%(ordering)s%(separator)s)',
separator=' SEPARATOR \'%s\'' % separator)
def as_sql(self, compiler, connection, **extra):
return super().as_sql(compiler,
connection,
template='%(function)s(%(distinct)s%(expressions)s%(ordering)s)',
**extra)
- [Django]-Variable subtraction in django templates
- [Django]-Django how to partial render
- [Django]-How do I use CSS in Django?
1๐
I just wanted to say a word of caution if you go with any of the proposed solutions for MySQL: by default, MySQL will truncate GROUP_CONCAT result to 1024 characters. Iโve spent some time figuring out why I was getting non-existent ids (they were truncated existent ids).
You can avoid the limitation by setting group_concat_max_len in Django settings. An example is here: Include multiple statements in Django's raw queries
- [Django]-Change the width of form elements created with ModelForm in Django
- [Django]-How do I rename a Django project in PyCharm?
- [Django]-Django InlineModelAdmin: Show partially an inline model and link to the complete model
0๐
this is the best way of working in Django ORM
f1 = Fruits.objects.values('type').annotate(count = Count('type'),namelist= GroupConcat('namelist')).distinct()
- [Django]-WARNING Not Found: /favicon.ico in Django
- [Django]-Django.core.exceptions.ImproperlyConfigured: Requested setting USE_I18N, but settings are not configured
- [Django]-Initial populating on Django Forms