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

group by two values and get the third values

我有一个包含三个 CharField 的 Django 模型,我想 运行 对其进行查询以获取它们两个的现有值,并为每个组合获取第三个字段的现有值。

    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 解决方案
from itertools import groupby

# Order by key fields so it will be easier to group later
items = YOUR_MODEL.objects.order_by('a', 'b')

# Group items by 'a' and 'b' fields as key
groups = groupby(items, lambda item: (item.a, item.b))

# Create dictionary with values as 'c' field from each item
res = {
    '-'.join(key): list(map(lambda item: item.c, group))
    for key, group in groups
}
# {'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 中执行 group_by 操作,并在您的查询集中创建一个名称为 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_fieldc 列。现在您所要做的就是序列化您的数据。

编辑 如果您想要特定格式的数据,您可以连接列 c。请阅读此 post 中 SO 接受的答案。 。然后,您可以在序列化期间创建一个新字段,它将 split() 串联的 c 字段放入列表中。