2013-06-30 33 views
7

我在Django(使用Postgres)中有以下模型模式。Django:快速检索manyToMany字段的ID

class A(Models.model): 
    related = models.ManyToManyField("self", null=True) 

给出的一个QuerySet,我想在查询集尽可能快地恢复一个字典映射的A每个实例的id开发它related实例列表越好。

我肯定可以迭代每个A并查询相关字段,但是有没有更优化的方法?

+0

你有没有得到这个解决方案? – cazgp

回答

8

根据你有三个实例。您可以使用values_list方法来检索结果,并从此结果中获取related实例的ID。 我使用pk字段做我的过滤器,因为我不知道你的方案,但你可以使用任何东西,只需要一个QuerySet

>>> result = A.objects.filter(pk=1) 
>>> result.values('related__id') 
[{'id': 2}, {'id': 3}] 
>>> result.values_list('related__id') 
[(2,), (3,)] 
>>> result.values_list('related__id', flat=True) 
[2, 3] 
+1

这就是我一直在做的,但问题是我需要过滤多个'pk'(例如'A.objects.filter(pk__in = [1,2,6])'')。我想要一个列表清单,其中第n个内部列表像这里的'values_list',但对应于第n个'pk'。 –

+0

如果您已经有单个模型实例,您也可以执行instance.related.values('id',flat = True)。 – alexcasalboni

0

你可以得到非常接近这样的:

qs = A.objects.prefetch_related(Prefetch(
         'related', 
         queryset=A.objects.only('pk'), 
         to_attr='related_insts')).in_bulk(my_list_of_pks) 

这会给出一个映射,从当前对象的实例本身PKS,这样你就可以遍历如下:

for pk, inst in qs.iteritems(): 
    related_ids = (related.pk for related in inst.related_insts) 

或者给出一个实例,你可以做一个快速查找,像这样:

related_ids = (related.pk for related in qs[instance.pk]). 

由于您特别请求了字典,因此此方法会将实例ID映射到相关的ID(间接)。如果你不这样做的查找,您可能要改为以下内容:

qs = A.objects.prefetch_related(Prefetch(
     'related', 
     queryset=A.objects.only('pk'), 
     to_attr='related_insts')).filter(pk__in=my_list_of_pks) 
for inst in qs: 
    related_ids = (related.pk for related in inst.related_insts) 

您可能会注意到使用only的只从DB拉PKS。有一个open ticket允许在预取查询中使用values和(我假设)values_list。这将允许您执行以下操作。

qs = A.objects.prefetch_related(Prefetch(
     'related', 
     queryset=A.objects.values_list('pk', flat=True), 
     to_attr='related_ids')).filter(pk__in=my_list_of_pks) 
for inst in qs: 
    related_ids = inst.related_ids 

你当然可以进一步优化,例如通过在主查询集使用qs.only('related_insts'),但要确保你没有做任何与这些instances--他们基本上只是昂贵的容器来保存你的related_ids。

我相信这是现在最好的(没有自定义查询)。为了得到你想要什么,还需要两两件事:

  1. 上述特征实现
  2. values_list由像它的注解与预取to_attr工作。

有了这两样东西(并继续上面的例子),你可以做到以下几点得到正是你要求:

d = qs.values_list('related_ids', flat=True).in_bulk() 
for pk, related_pks in d: 
    print 'Containing Objects %s' % pk 
    print 'Related objects %s' % related_pks 
# And lookups 
print 'Object %d has related objects %s' % (20, d[20]) 

我已经离开了一些细节解释的事情,但它应该从文档中很清楚。如果您需要澄清,请不要犹豫!