Django:快速检索manyToMany字段的ID

时间:2013-06-30 07:41:56

标签: python database django postgresql m2m

我在Django中使用以下模型架构(使用Postgres)。

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

给定A的QuerySet,我想返回一个字典,将QuerySet中A的每个实例尽快映射到id个实例的related列表中。

我可以肯定地遍历每个A并查询相关字段,但是有更优化的方法吗?

2 个答案:

答案 0 :(得分:10)

据你有三个例子。您可以使用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 :(得分: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仅从数据库中提取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'),但请确保您不对这些实例执行任何操作 - 它们基本上只是昂贵的容器抓住你的related_ids。

我相信这是目前最好的(没有自定义查询)。为了得到你想要的东西,需要做两件事:

  1. 实施上述功能
  2. values_list与Prefetch to_attr一样,可以像注释一样使用。
  3. 有了这两件事(并继续上面的例子),您可以执行以下操作以获得您所要求的内容:

    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])
    

    我已经省略了解释事情的一些细节,但是从文档中可以很清楚。如果您需要任何澄清,请不要犹豫!