如何优化相关对象的延迟加载,如果我们已经有了它的实例?

2024-04-26 18:22:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我喜欢Django ORM lazy在queryset中加载相关对象的方式,但我猜这是相当不可预测的。 当相关对象用于创建queryset时,querysetapi不会保留它们,因此在以后访问时会再次获取它们。你知道吗

假设我有一个ModelA实例(例如实例a),它是ModelB的一些N个实例的外键(例如)。现在我想对ModelB执行查询,它将给定的ModelA实例作为外键。你知道吗

Django ORM提供两种方法:

  • 在ModelB上使用.filter()
b_qs = ModelB.objects.filter(for_a=instance_a)
for instance_b in b_qs:
    instance_b.for_a # <-- fetches the same row for ModelA again

在这里产生1+N个查询。你知道吗

  • ModelA实例上使用反向关系:
b_qs = instance_a.for_a_set.all()
for instance_b in b_qs:
    instance_b.for_a # <-- this uses the instance_a from memory

仅在此处生成一个查询。你知道吗

虽然第二种方法可以用来实现结果,但它不是标准API的一部分,也不适用于所有场景。例如,如果我有两个ModelB外键的实例(比如说,ModelAModelC),我想得到它们的相关对象。 类似于以下工作:

ModelB.objects.filter(for_a=instance_a, for_c=instance_c)

我想在这个场景中使用.intersection()是可能的,但是我想通过标准API实现这一点。毕竟,覆盖这些情况需要更多带有非标准queryset函数的代码,这对下一个开发人员来说可能没有意义。你知道吗

所以,第一个问题,是否有可能用标准API本身来优化这些场景? 第二个问题,如果现在不可能,是否可以在QuerySet中添加一些调整?你知道吗

PS:这是我第一次在这里问问题,如果我犯了任何错误,请原谅。你知道吗


Tags: 对象django实例instanceapifor标准orm
2条回答

^{} [Django-doc]表示ForeignKey,用^{} [Django-doc]表示多对多关系。你知道吗

使用.select_related(..),您将在数据库端创建一个LEFT OUTER JOIN,并获取两个对象的记录,从而对适当的对象进行反序列化。你知道吗

ModelB.objects.select_related('for_a').filter(for_a=instance_a)

对于一对多关系(即反向的ForeignKey)或ManyToManyField,这不是一个好主意,因为它可能会导致检索到大量重复的对象。这将导致从数据库得到一个大的答案,并且在Python端需要做大量的工作来反序列化这些对象。.prefetch_related将进行单独的查询,然后自己进行链接。你知道吗

您可以使用^{}改进查询:

b_qs = ModelB.objects.select_related('for_a').filter(for_a=instance_a)

或者

b_qs = instance_a.for_a_set.select_related('for_a')

有帮助吗?你知道吗

相关问题 更多 >