问题描述
我有一个名为MyModel的模型,它有一些虚拟数据如下: 项目日期值
- ----------------------------
ab 8/10/12 124
ab 7/10/12 433
ab 6/10/12 99
abc 8/10/12 23
abc 7/10/12 80
我想以这样的方式查询此模型,我得到如下输出:
[{'item':'ab','values':[124,433,99]},
{'item':'abc','values':[23,80] }]
我如何使用django ORM来执行此操作?
(Apr 4 '16)更新:这是Django的一个工作解决方案。对于较新版本,请阅读( )
定义这个:
类Concat(models.Aggregate):
def add_to_query(self,query,alias,col,source,is_summary):
#we send source = CharField以防止Django将字符串转换为int
aggregate = SQLConcat(col,source = models.CharField(),is_summary = is_summary,** self.extra)
查询。聚合[alias] = aggregate
#for mysql
class SQLConcat(models.sql.aggregates.Aggregate):
sql_func ='group_concat'
@property
def sql_template(self):
if self.extra.get('separator'):
return'% )s(%(field)s SEPARATOR%(separator)s)'
else:
return'%(function)s(%(field)s)'
#For PostgreSQL> = 9.0
#与分隔符一起使用,例如.annotate(value = Concat('value',separator =','))
class SQLConcat(models.sql.aggregates.Aggregate):
sql_function ='string_agg'
@property
def sql_template(self):
#the :: text cast是一个使用整数列处理的硬编码的hack
return%(function)s(%(field)s: :text,'%(separator)s')
#For PostgreSQL> = 8.4和< 9.0
#与分隔符一起使用,例如.annotate(values = Concat('value',separator =','))
class SQLConcat(models.sql.aggregates.Aggregate):
sql_function ='array_to_string'
@property
def sql_template(self):
return%(function)s(array_agg(%(field)s),'%(separator)s')
#For PostgreSQL< 8.4你应该在使用它之前定义array_agg:
#CREATE AGGREGATE array_agg(anyelement)
#(
#sfunc = array_append,
#stype = anyarray,
#initcond ='{}'
#);
class MyModel(models.Model):
item = models.CharField(max_length = 255)
date = models.DateTimeField()
value = models.IntegerField ()
所以现在你可以做:
>>>从my_app.models导入MyModel,Concat
>>> MyModel.objects.values('item')。annotate(values = Concat('value'))
[{'item':u'ab','values':u'124,433,99'},{ 'item':u'abc','values':u'23,80'}]
要获取值
作为您需要手动 .split
并转换为 int的整数列表
。如下所示:
>>> my_list = MyModel.objects.values('item')。annotate(values = Concat('value'))
>>>因为我在my_list中:
... i ['values'] = [int(v)for v in i ['values']。split(',')]
...
>>>> my_list
[{'item':u'ab','values':[124,433,99]},{'item':u'abc','values':[23,80]}]
I have a model called MyModel which has some dummy data as follows:
item date value
------------------------------
ab 8/10/12 124
ab 7/10/12 433
ab 6/10/12 99
abc 8/10/12 23
abc 7/10/12 80
I would like to query this Model in such a way that i get an output as follows:
[{'item': 'ab', 'values': [ 124, 433, 99]},
{'item': 'abc', 'values': [ 23, 80]}]
How would i be able to do this using the django ORM?
(Apr 4 '16) UPDATE: This is a working solution for Django <= 1.7. For newer versions please read Creating your own Aggregate Functions from the docs.
Using a custom Concat
aggregate taken from here (an article about the topic)
Define this:
class Concat(models.Aggregate):
def add_to_query(self, query, alias, col, source, is_summary):
#we send source=CharField to prevent Django from casting string to int
aggregate = SQLConcat(col, source=models.CharField(), is_summary=is_summary, **self.extra)
query.aggregates[alias] = aggregate
#for mysql
class SQLConcat(models.sql.aggregates.Aggregate):
sql_function = 'group_concat'
@property
def sql_template(self):
if self.extra.get('separator'):
return '%(function)s(%(field)s SEPARATOR "%(separator)s")'
else:
return '%(function)s(%(field)s)'
#For PostgreSQL >= 9.0
#Aways use with separator, e.g. .annotate(values=Concat('value', separator=','))
class SQLConcat(models.sql.aggregates.Aggregate):
sql_function = 'string_agg'
@property
def sql_template(self):
#the ::text cast is a hardcoded hack to work with integer columns
return "%(function)s(%(field)s::text, '%(separator)s')"
#For PostgreSQL >= 8.4 and < 9.0
#Aways use with separator, e.g. .annotate(values=Concat('value', separator=','))
class SQLConcat(models.sql.aggregates.Aggregate):
sql_function = 'array_to_string'
@property
def sql_template(self):
return "%(function)s(array_agg(%(field)s), '%(separator)s')"
#For PostgreSQL < 8.4 you should define array_agg before using it:
#CREATE AGGREGATE array_agg (anyelement)
#(
# sfunc = array_append,
# stype = anyarray,
# initcond = '{}'
#);
class MyModel(models.Model):
item = models.CharField(max_length = 255)
date = models.DateTimeField()
value = models.IntegerField()
so now you can do:
>>> from my_app.models import MyModel, Concat
>>> MyModel.objects.values('item').annotate(values=Concat('value'))
[{'item': u'ab', 'values': u'124,433,99'}, {'item': u'abc', 'values': u'23,80'}]
to get values
as a list of integers you need to manually .split
and cast to int
. Something like:
>>> my_list = MyModel.objects.values('item').annotate(values=Concat('value'))
>>> for i in my_list:
... i['values'] = [int(v) for v in i['values'].split(',')]
...
>>> my_list
[{'item': u'ab', 'values': [124, 433, 99]}, {'item': u'abc', 'values': [23, 80]}]
这篇关于Django通过模型中的另一个字段分组列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!