2012-04-26 53 views
12

說,我有如下表稱爲fruitsGROUP_CONCAT相當於在Django

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

我的目標是最終拿出不同types的計數和一個逗號分隔的names的列表:

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

這可以很容易地在MySQL中使用GROUP_CONCAT完成,但我在Django等價物中遇到了問題。這是我迄今爲止,但我缺少的東西GROUP_CONCAT

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

我想盡可能避免使用原始的SQL查詢。

任何幫助將不勝感激!

謝謝! =)

回答

3

Django ORM不支持這個;如果你不想使用原始SQL,那麼你需要group and join

+1

我的一位同事認爲,像暴露在Django GROUP_CONCAT MySQL的具體功能的開源項目。看看https://github.com/adamchainz/django-mysql/ – 2015-07-23 13:36:34

3

如果你不介意在您的模板做這個Django模板標籤regroup實現這一

1

通過Django的ORM不支持,但你可以建立自己的聚合。

這其實很簡單,這裏是一個如何做,不只是一個鏈接,與GROUP_CONCAT SQLite的:http://harkablog.com/inside-the-django-orm-aggregates.html

不過請注意,這可能需要分別處理不同的SQL方言。例如,SQLite docs say about group_concat

級聯元素的順序是任意的

雖然MySQL allows you to specify the order

我想這可能是爲什麼GROUP_CONCAT它目前尚未在Django中實現。

22

您可以創建自己的聚合函數(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

+0

這太神奇了!它也適用於SQLLite! – 2015-09-08 23:34:05

+1

注意Django(> = 1.8)提供['數據庫函數'](http://stackoverflow.com/a/40478702/2714931) – WeizhongTu 2017-01-24 06:05:13

3

由於Django 1.8可以使用Func() expressions

query_set = Fruits.objects.values('type').annotate(count=Count('type'), name = Func(F('name'), 'GROUP_BY')).order_by('-count') 
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'}] 
5

注意到,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') 
+0

它不適用於我。 另一個很好的例子: https://gist.github.com/ludoo/ca6ed07e5c8017272701 – 2017-04-18 19:42:17

+0

@ Iliaw495Nikitin這個效果很好,在我的項目中使用Django 1.10.x – WeizhongTu 2017-04-19 02:42:48

+0

在Django 1.11.x中很好地工作。謝謝! – d345k0 2017-04-20 14:24:26