Django Queryset:将两个查询集与一个查询集连接为列表或集合

时间:2020-06-04 15:11:49

标签: django join django-queryset

我有两个单独的查询集(A和B),其中一个与另一个具有外键关系(1对很多,其中B很多)。是否有可能以某种方式将两个查询集结合在一起,创建一个看起来像这样的对象:

A: 
{
   some_field: ...,
   list_of_B: [...],
}

通过迭代A的值并添加字段,我已经找到了一个相对较慢的解决方案:

for i in range(len(A.values())):
    result[i] = A[i]
    result[i]['list_of_B'] = list(B.filter(fk_in_B=A[i]['id']))

出于性能方面的考虑,我希望在查询集中执行此操作。甚至可能在查询集的字段/列中有列表/集?如果是这样,有什么可能的方法?

编辑:一些其他信息。

这是关于的模型。

A:

class Scan(models.Model):
    <some unrelated fields>

B:

class Image(models.Model):
    scan = models.ForeignKey(Scan, on_delete=models.SET_NULL, null=True)
    <some unrelated fields>

我正在运行的查询:

scans = Scan.objects.all() \
    .select_related(<select some FK field>);

images = Image.objects.filter(scan__in=scans.values_list('id', flat=True)) \
    .annotate(some_field=F(<some field>)) \
    .annotate(another_field=F(<another field>)) \
    .values('scan', 'some_field', 'another_field') \
    .annotate(count=Count('id')); # I want to know the amount of combinations between my values

# combining the queries inefficiently:
scans = scans.values()
result = {}
for i in range(len(scans)):
    result[i] = scans[i]
    result[i]['images'] = list(images.filter(scan=scans[i]['id']))

1 个答案:

答案 0 :(得分:0)

在我看来,您可能会受益于在初始查询集A上使用select_related的情况。这将导致它在数据库中进行联接并返回所有数据,而无需再对数据库进行查询。更大,更复杂的初始查询的成本。

如果您的查询集B具有过滤器,则需要将它们作为相关字段移动到查询A中,例如.filter(image__some_property=some_val)

docs解释得很好。

如果这完全不适合您的情况,我的后备建议是从您的查询集B构建一个字典,以对fk值建立索引。这将加快您遍历A的值以过滤B的方法-每次都在进行新的数据库查询。假设B不是太大,以至于无论如何它都不能舒适地容纳在内存中。但是,如果可能的话,最好使用联接。