postgresql Django:快速检索 manyToMany 字段的 ID

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17388254/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 00:59:21  来源:igfitidea点击:

Django: Retrieving IDs of manyToMany fields quickly

pythondatabasedjangopostgresqlm2m

提问by Noah Gilmore

I have the following model schema in Django (with Postgres).

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

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

Given a QuerySet of A, I would like to return a dictionary mapping each instance of Ain the QuerySet to a list of ids of its relatedinstances as quickly as possible.

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

I can surely iterate through each A and query the related field, but is there a more optimal way?

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

回答by Luan Fonseca

According you have Three instances. You can use the values_listmethod to retrieve just the results and from this result get just the ID's of their relatedinstances. I use the pkfield to be my filter because i don't know your scheme, but you can use anything, just must be a QuerySet.

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

回答by DylanYoung

You can get pretty close like this:

你可以像这样接近:

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

This will give a mapping from pks of the current object to the instance itself, so you can iterate through as follows:

这将给出从当前对象的 pks 到实例本身的映射,因此您可以按如下方式进行迭代:

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

Or given an instance, you can do a fast lookup like so:

或者给定一个实例,您可以像这样进行快速查找:

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

This method maps the instance ids to the related ids (indirectly) since you specifically requested a dictionary. If you aren't doing lookups, you may want the following instead:

此方法将实例 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)

You may take note of the use of onlyto only pull the pks from the db. There is an open ticketto allow the use of valuesand (I presume) values_listin Prefetch queries. This would allow you to do the following.

您可能会注意到使用only仅从数据库中提取 pks。有一个开放票允许在预取查询中使用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

You could of course optimize further, for example by using qs.only('related_insts')on the primary queryset, but make sure you aren't doing anything with these instances-- they're essentially just expensive containers to hold your related_ids.

您当然可以进一步优化,例如通过qs.only('related_insts')在主查询集上使用,但请确保您没有对这些实例做任何事情——它们本质上只是用于保存您的 related_ids 的昂贵容器。

I believe this is the best that's available for now (without custom queries). To get to exactly what you want, two things are needed:

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

  1. The feature above is implemented
  2. values_listis made to work with Prefetch to_attrlike it does for annotations.
  1. 上面的功能实现了
  2. values_list与 Prefetch 一起使用,to_attr就像注释一样。

With these two things in place (and continuing the above example) you could do the following to get exactly what you requested:

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

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

I've left off some details explaining things, but it should be pretty clear from the documentation. If you need any clarification, don't hesitate!

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