Django3预取_相关

Django3预取_相关,django,django-3.0,Django,Django 3.0,我曾为django 2.X工作过。但是我将在我的新项目中使用django3.x。 在版本2,我应该进行外部连接。我使用了prefetch\u related并过滤了prefetch\u related的模型 在版本2中,如果我使用prefetch\u related,它将作为单个查询进行查询。但在版本3中,通过多个查询进行查询 如果我只使用连接目标的Q(),而不使用与预取相关的,那么它可以在版本3进行单次查询 from django.db import models from django.db

我曾为django 2.X工作过。但是我将在我的新项目中使用django3.x。 在版本2,我应该进行外部连接。我使用了
prefetch\u related
并过滤了
prefetch\u related
的模型

在版本2中,如果我使用
prefetch\u related
,它将作为单个查询进行查询。但在版本3中,通过多个查询进行查询

如果我只使用连接目标的Q(),而不使用与预取相关的,那么它可以在版本3进行单次查询

from django.db import models
from django.db.models import Q
from django.db.models import Prefetch


class Member(models.Model):
    member_no = models.AutoField()
    member_name = models.CharField()


class Permission(models.Model):
    permission_no = models.AutoField()


class MemberPermission(models.Model):
    member_permission_no = models.AutoField()
    member_no = models.ForeignKey(
        Member, related_name='members', on_delete=models.CASCADE,
    )
    permission_no = models.ForeignKey(
        Permission, related_name='member_permissions', on_delete=models.CASCADE,
    )


my_permission = Member.objects.prefetch_related('member_permissions').filter(Q(member_permissions__isnull=False))[:1]
print(my_permission[0].member_permissions)  
# member outer join permission, single query at django 2.X
# member outer join permission & additional query at django 3.x

my_permission = Member.objects.filter(Q(member_permissions__isnull=False))[:1]
print(my_permission[0].member_permissions)  
# member outer join permission, single query at django 3.X

my_permission = Member.objects.prefetch_related(
                    Prefetch('member_permissions', MemberPermission.objects.select_related(
                        'permission_no').all())
                ).filter(Q(members__isnull=False))[:1]
print(my_permission[0].member_permissions.all()[0].permission_no.permission_no)
# member outer join permission & additional query at django 3.x

如果我不使用
预取\u related
,我可以得到一个查询

但如果我想获得加入模型的模型(成员权限Permission by Member),它就不能


我想知道如何通过django3中的
Prefetch()
查询一次。

这不是版本差异。这是
预取相关
的工作方式。它将对每个外部联接执行1个额外查询。然而,这仍然比每次迭代执行一个查询要少得多。关于这一点,我们的立场非常明确:

通过创建SQL联接并在select语句中包含相关对象的字段来选择与_相关的工作。因此,select_related将获取同一数据库查询中的相关对象。但是,为了避免跨“多”关系加入会导致更大的结果集,select_related仅限于单值关系-外键和一对一

另一方面,prefetch_-related对每个关系执行单独的查找,并在Python中执行“连接”。这允许它预取多对多和多对一对象,这是使用select_-related无法完成的,此外,select_-related还支持外键和一对一关系

假设我们有两个外部联接,总共有1000个匹配行:

  • 无预取相关的查询数:1+2*1000=2001
  • 与预回迁相关的查询数:1+2=3

因此,担心每个连接有一个额外的查询是没有意义的。

您如何确定这是由版本差异造成的?您是否创建了一个计算查询数量的测试,然后在两个不同的虚拟环境中运行它(使用[tox](例如)是否要显示问题?@Melvyn很抱歉我弄错了。我已尝试由venvs作为您的评论。它的执行方式相同而无差异。如果我使用“预回迁相关”并尝试获取列,是否总是执行多个查询?