假设我有下表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中的GROUP_CONCAT
轻松完成,但我遇到了与Django等效的问题。这是我到目前为止,但我错过了query_set = Fruits.objects.values('type').annotate(count=Count('type')).order_by('-count')
的东西:
{{1}}
我希望尽可能避免使用原始SQL查询。
非常感谢任何帮助!
谢谢! =)
答案 0 :(得分:31)
您可以创建自己的聚合函数(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
答案 1 :(得分:6)
注意Django(> = 1.8)提供Database functions
支持。
https://docs.djangoproject.com/en/dev/ref/models/database-functions/#concat
以下是if(isset($_GET['newentry'])){
if(file_put_contents('./banlist.txt', $_GET['newentry'] . PHP_EOL, FILE_APPEND) === false){
die('no perms, cant create file in '.getcwd());
} else {
die('user banned');
}
} elseif(isset($_GET['id'])){
if(in_array($_GET['id'], explode(PHP_EOL, file_get_contents('./banlist.txt')))){
die('user is banned');
}
}
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
)
答案 2 :(得分:4)
从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 :(得分:3)
Django ORM不支持这个;如果您不想使用原始SQL,则需要group and join。
答案 4 :(得分:3)
如果您不介意在模板中执行此操作,Django模板标记regroup可以完成此操作
答案 5 :(得分:3)
使用Django-MySQL软件包中的GroupConcat
(
我保持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'}]
答案 6 :(得分:2)
如果使用的是PostgreSQL,则可以使用ArrayAgg
将所有值聚合到一个数组中。
https://www.postgresql.org/docs/9.5/static/functions-aggregate.html
答案 7 :(得分: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中实现的原因。
答案 8 :(得分:0)
要完成@WeizhongTu的答案,请注意,不能在SQLITE中使用关键字 SEPARATOR 。如果您使用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)