我有一个带有三个CharFields的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]}}
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_field
列和c
列。现在您所要做的就是序列化数据。
编辑如果您希望数据采用该特定格式,则可以连接列c
。请阅读这篇文章中 SO 接受的答案。Django 在模型中按另一个字段分组的字段列表。然后,您可以在序列化期间创建一个新字段,该字段会将串联的c
字段split()
到列表中。
想不出好的纯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']}