Ответ 1
Django ORM не поддерживает это; если вы не хотите использовать необработанный SQL, вам нужно группу и присоединиться.
Скажем, у меня есть следующая таблица под названием 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-запросов, если это возможно.
Любая помощь будет принята с благодарностью!
Спасибо! =)
Django ORM не поддерживает это; если вы не хотите использовать необработанный SQL, вам нужно группу и присоединиться.
Вы можете создать свою собственную функцию агрегации (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)
и использовать его просто как:
query_set = Fruits.objects.values('type').annotate(count=Count('type'),
name = Concat('name')).order_by('-count')
Я использую django 1.8 и mysql 4.0.3
УВЕДОМЛЕНИЕ о том, что 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
)
Использование:
LogModel.objects.values('level', 'info').annotate(
count=Count(1), time=GroupConcat('time', ordering='time DESC', separator=' | ')
).order_by('-time', '-count')
Если вы не возражаете сделать это в своем шаблоне, тег шаблона Django regroup выполняет этот
По Django 1.8 вы можете использовать выражения Func().
query_set = Fruits.objects.values('type').annotate(count=Count('type'), name = Func(F('name'), 'GROUP_BY')).order_by('-count')
Используйте 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'}]
Не поддерживается Django ORM, но вы можете создать собственный агрегатор.
На самом деле это довольно просто, вот ссылка на руководство, которое делает именно это, с GROUP_CONCAT
для SQLite: http://harkablog.com/inside-the-django-orm-aggregates.html
Обратите внимание, что, возможно, потребуется отдельно обрабатывать разные диалекты SQL. Например, SQLite docs говорят о GROUP_CONCAT
:
Порядок конкатенированных элементов произвольный
Пока MySQL позволяет указать порядок.
Я предполагаю, что это может быть причиной того, что GROUP_CONCAT
он не реализован в Django на данный момент.