Django:快速检索manyToMany字段的ID

Posted

技术标签:

【中文标题】Django:快速检索manyToMany字段的ID【英文标题】:Django: Retrieving IDs of manyToMany fields quickly 【发布时间】:2013-06-27 14:48:23 【问题描述】:

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

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

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

我当然可以遍历每个A并查询相关字段,但是有没有更优化的方法?

【问题讨论】:

你有没有解决这个问题? 【参考方案1】:

你可以这样接近:

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'),但请确保您不对这些实例做任何事情——它们本质上只是用于保存您的相关 ID 的昂贵容器。

我相信这是目前最好的(没有自定义查询)。要达到您想要的效果,需要做两件事:

    上述功能已实现 values_list 可与 Prefetch to_attr 一起使用,就像对注释一样。

有了这两件事(并继续上面的示例),您可以执行以下操作以获得您所要求的内容:

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

我省略了一些解释事情的细节,但从文档中应该很清楚。如果您需要任何说明,请不要犹豫!

【讨论】:

【参考方案2】:

根据您有三个实例。您可以使用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]

【讨论】:

这就是我一直在做的事情,但问题是我需要过滤多个pk(例如A.objects.filter(pk__in=[1,2,6]))。我想要一个列表列表,其中第 n 个内部列表就像这里的 values_list,但对应于第 n 个 pk 如果您已经有一个模型实例,您也可以执行 instance.related.values('id', flat=True)。 result.values_list 这些天似乎返回了一个查询集。可以使用list(result.values_list) 轻松将其转换回列表

以上是关于Django:快速检索manyToMany字段的ID的主要内容,如果未能解决你的问题,请参考以下文章

如何更新Django 的ManyToMany 字段

Django:模型设计,ManyToMany 属性字段?

Django上ManyToMany字段的唯一值

Django:检查模板中ManyToMany字段中的值

Django 1.4 - ManyToMany 字段看起来像用户身份验证中的用户权限字段

使用 Django admin 时未保存 ManyToMany 字段