Вопрос по mysql – Эквивалент GROUP_CONCAT в Джанго

13

Скажем, у меня есть следующая таблица под названиемfruits:

id | type   | name
-----------------
 0 | apple  | fuji
 1 | apple  | mac
 2 | orange | navel

Моя цель состоит в том, чтобы в конечном итоге придуматьtypes и разделенный запятыми списокnames:

apple, 2, "fuji,mac"
orange, 1, "navel"

Это может быть легко сделано сGROUP_CONCAT в MySQL, но у меня проблемы с эквивалентом Django. Это то, что я до сих пор, но я скучаю поGROUP_CONCAT материал:

query_set = Fruits.objects.values('type').annotate(count=Count('type')).order_by('-count')

Я хотел бы избежать использования сырых запросов SQL, если это возможно.

Любая помощь будет принята с благодарностью!

Спасибо! знак равно

Ваш Ответ

9   ответов
2

ArrayAgg агрегировать все значения в массив.

https://www.postgresql.org/docs/9.5/static/functions-aggregate.html

4

Выражения Func ().

query_set = Fruits.objects.values('type').annotate(count=Count('type'), name = Func(F('name'), 'GROUP_BY')).order_by('-count')
31

доктор)

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)

и используйте его просто как:

query_set = Fruits.objects.values('type').annotate(count=Count('type'),
                       name = Concat('name')).order_by('-count')

Я использую django 1.8 и mysql 4.0.3

Error: User Rate Limit ExceededDatabase functions
Error: User Rate Limit Exceeded
1

но вы можете создать свой собственный агрегатор.

Это на самом деле довольно просто, вот ссылка на инструкцию, которая делает именно это, сGROUP_CONCAT для SQLite:http://harkablog.com/inside-the-django-orm-aggregates.html

Обратите внимание, однако, что может потребоваться обрабатывать разные диалекты SQL отдельно. Например,Документы SQLite говорят оgroup_concat:

The order of the concatenated elements is arbitrary

В то время какMySQL позволяет указывать порядок.

Я думаю, это может быть причиной, почемуGROUP_CONCAT в настоящее время он не реализован в Django.

6

= 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
        )

Использование:

LogModel.objects.values('level', 'info').annotate(
    count=Count(1), time=GroupConcat('time', ordering='time DESC', separator=' | ')
).order_by('-time', '-count')
Error: User Rate Limit Exceededgist.github.com/ludoo/ca6ed07e5c8017272701
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
3

использование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'),
...     types_list=GroupConcat('type'),
... ).order_by('-count').values('type', 'count', 'types_list')
[{'type': 'apple', 'count': 2, 'types_list': 'fuji,mac'},
 {'type': 'orange', 'count': 1, 'types_list': 'navel'}]
3

перегруппировывать выполняет это

0

обратите внимание, что вы не можете использовать ключевое словоSEPARATOR с SQLITE. В тех случаях, когда вы используете MySQL и SQLite для своих тестов, вы можете написать:

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)
3

если вы не хотите использовать сырой SQL, тогда вам нужногруппа и присоединиться.

Error: User Rate Limit Exceededgithub.com/adamchainz/django-mysql

Похожие вопросы