Django中的GROUP_CONCAT等价物

All*_*Liu 15 mysql django group-concat

说我有下面的表格fruits:

id | type   | name
-----------------
 0 | apple  | fuji
 1 | apple  | mac
 2 | orange | navel
Run Code Online (Sandbox Code Playgroud)

我的目标是最终得到一个不同types的逗号和逗号分隔的列表names:

apple, 2, "fuji,mac"
orange, 1, "navel"
Run Code Online (Sandbox Code Playgroud)

这可以GROUP_CONCAT在MySQL中轻松完成,但我遇到了与Django等效的问题.这是我到目前为止,但我错过了GROUP_CONCAT这些东西:

query_set = Fruits.objects.values('type').annotate(count=Count('type')).order_by('-count')
Run Code Online (Sandbox Code Playgroud)

我想尽可能避免使用原始SQL查询.

任何帮助将不胜感激!

谢谢!=)

Sha*_*gla 36

您可以创建自己的聚合函数(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)
Run Code Online (Sandbox Code Playgroud)

并简单地用作:

query_set = Fruits.objects.values('type').annotate(count=Count('type'),
                       name = Concat('name')).order_by('-count')
Run Code Online (Sandbox Code Playgroud)

我使用的是django 1.8和mysql 4.0.3

  • 这真太了不起了!它也可以在SQLLite上运行! (2认同)
  • 为了完整起见,还有:`django.contrib.postgres.aggregates.StringAgg`,以防您在 Postgres 中需要相同的内容 (2认同)
  • 该函数也存在于“django-mysql”中:https://django-mysql.readthedocs.io/en/latest/aggregates.html?highlight=GroupConcat#django_mysql.models.GroupConcat (2认同)
  • 对于 django 2.2,我需要将 `allow_distinct = True` 添加到 Concat 类 (2认同)

Ada*_*inz 8

使用我维护GroupConcat的 Django-MySQL 包 ( https://django-mysql.readthedocs.org/en/latest/aggregates.html#django_mysql.models.GroupConcat )。有了它,你可以简单地做到:

>>> 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'}]
Run Code Online (Sandbox Code Playgroud)


Wei*_*gTu 8

注意Django(> = 1.8)提供Database functions支持. https://docs.djangoproject.com/en/dev/ref/models/database-functions/#concat

这是一个增强版 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
        )
Run Code Online (Sandbox Code Playgroud)

用法:

LogModel.objects.values('level', 'info').annotate(
    count=Count(1), time=GroupConcat('time', ordering='time DESC', separator=' | ')
).order_by('-time', '-count')
Run Code Online (Sandbox Code Playgroud)


Ign*_*ams 2

Django ORM 不支持这一点;如果你不想使用原始 SQL 那么你需要group 和 join

  • 我的一位同事维护着一个开源项目,该项目公开了 mysql 特定函数,例如 django 中的 GROUP_CONCAT。看看 https://github.com/adamchainz/django-mysql/ (2认同)