Django 按两个值分组并获得第三个值

Django 按两个值分组并获得第三个值,django,django-orm,Django,Django Orm,我有一个Django模型,它有三个charfield,我想对这三个charfield运行一个查询,以获取其中两个字段的现有值,并为每个组合获取第三个字段的现有值 a = models.CharField(null=False, max_length=8000) b = models.CharField(null=False, max_length=8000) c = models.CharField(null=False, max_length=8000) 如果假设这些

我有一个Django模型,它有三个charfield,我想对这三个charfield运行一个查询,以获取其中两个字段的现有值,并为每个组合获取第三个字段的现有值

    a = models.CharField(null=False, max_length=8000)
    b = models.CharField(null=False, max_length=8000)
    c = models.CharField(null=False, max_length=8000)
如果假设这些值在数据库中:

 a  | b  | c  |
---------------
 a1 | b2 | c3 |
 a1 | b2 | c1 |
 a2 | b2 | c3 |
 a1 | b3 | c3 |
 a1 | b2 | c2 |
我希望在此表单中得到一些结果:

{"a1-b2" : [c3, c1, c2], "a2-b2" : [c3], "a1-b3" : [c3]}
or 
{"a1" : {"b2":[c3, c1, c2], "b3": [c3]}, "a2": {"b2" : [c3]}} 

我想不出好的纯SQL解决方案,但这里有一个使用
groupby
的pythonic解决方案:

从itertools导入groupby
#按键字段排序,以便以后更容易分组
items=您的模型.objects.order按('a','b')排序
#按“a”和“b”字段作为键对项目进行分组
分组=分组依据(项目,lambda项目:(项目a,项目b))
#创建字典,每个项目的值为“c”字段
res={
'-'.join(键):列表(映射(lambda项:item.c,group))
对于键,在组中分组
}
#{'a1-b2':['c3','c1','c2'],'a1-b3':['c3'],'a2-b2':['c3']}

想不出好的纯SQL解决方案,但下面是一个使用
groupby
的pythonic解决方案:

从itertools导入groupby
#按键字段排序,以便以后更容易分组
items=您的模型.objects.order按('a','b')排序
#按“a”和“b”字段作为键对项目进行分组
分组=分组依据(项目,lambda项目:(项目a,项目b))
#创建字典,每个项目的值为“c”字段
res={
'-'.join(键):列表(映射(lambda项:item.c,group))
对于键,在组中分组
}
#{'a1-b2':['c3','c1','c2'],'a1-b3':['c3'],'a2-b2':['c3']}

TLDR:

items = MyModel.objects.annotate(custom_field=Concat('a', Values('-'), 'b').values('custom_field', 'c')
解释

使用部分
.annotate(custom_field=Concat('a',Values('-'),'b')
),您基本上是在SQL中按操作分组,并在查询集中创建一个名为
custom_field
的临时新列,该列的值将为
a-b

这将为您提供以下结构:

a    |    b    |    c    | custom_field
a1        b1        c1          a1-b1
a2        b2        c2          a2-b2 
a1        b1        c3          a1-b1
.values('custom_field','c')
部分仅从该查询集中获取
custom_field
c
列。现在您所要做的就是序列化数据

编辑
如果您希望您的数据采用该特定格式,您可以将列
c
连接起来。请阅读本文中接受的答案。然后,您可以在序列化过程中创建一个新字段,该字段将
拆分()
连接的
c
字段到一个列表中。

TLDR:

items = MyModel.objects.annotate(custom_field=Concat('a', Values('-'), 'b').values('custom_field', 'c')
解释

使用部分
.annotate(custom_field=Concat('a',Values('-'),'b')
),您基本上是在SQL中按操作分组,并在查询集中创建一个名为
custom_field
的临时新列,该列的值将为
a-b

这将为您提供以下结构:

a    |    b    |    c    | custom_field
a1        b1        c1          a1-b1
a2        b2        c2          a2-b2 
a1        b1        c3          a1-b1
.values('custom_field','c')
部分仅从该查询集中获取
custom_field
c
列。现在您所要做的就是序列化数据

编辑 如果您希望数据采用该特定格式,可以将列
c
连接起来。请阅读本文中接受的答案。然后,您可以在序列化过程中创建一个新字段,该字段将
split()
连接的
c
字段拆分为一个列表