鸡 prefetch_related
Django3 prefetch_related
我曾在 django 2.X 工作过。但我将在我的新项目中使用 django3.x。
在 version2,当我应该进行外部连接时。我使用 prefetch_related
并过滤了 prefetch_related
的模型。
在版本 2 中,如果我使用 prefetch_related
,它会作为单个查询进行查询。但在版本 3 中,通过多个查询进行查询。
如果我只使用连接目标的 Q() 而没有 prefetch_related
,它可以在版本 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
如果我不使用 prefetch_related
,我可以获得单个查询。
但是如果我想获取加入模型的模型(MemberPermission的权限)它不能。
我想知道如何在django3中通过Prefetch()
查询一次
这不是版本差异。这就是 prefetch_related
的工作方式。它将为每个外部连接执行 1 个额外的查询。但是,这仍然比每次迭代执行 1 个查询少 lot。 documentation 说的很清楚了:
select_related works by creating an SQL join and including the fields of the related object in the SELECT statement. For this reason, select_related gets the related objects in the same database query. However, to avoid the much larger result set that would result from joining across a ‘many’ relationship, select_related is limited to single-valued relationships - foreign key and one-to-one.
prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using select_related, in addition to the foreign key and one-to-one relationships that are supported by select_related.
假设我们有 2 个外连接,总共有 1000 个匹配行:
- 没有prefetch_related的查询数:1 + 2*1000 = 2001
- prefetch_related 的查询数量:1 + 2 = 3
因此,不必担心每个连接的 1 个额外查询。
我曾在 django 2.X 工作过。但我将在我的新项目中使用 django3.x。
在 version2,当我应该进行外部连接时。我使用 prefetch_related
并过滤了 prefetch_related
的模型。
在版本 2 中,如果我使用 prefetch_related
,它会作为单个查询进行查询。但在版本 3 中,通过多个查询进行查询。
如果我只使用连接目标的 Q() 而没有 prefetch_related
,它可以在版本 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
如果我不使用 prefetch_related
,我可以获得单个查询。
但是如果我想获取加入模型的模型(MemberPermission的权限)它不能。
我想知道如何在django3中通过Prefetch()
查询一次
这不是版本差异。这就是 prefetch_related
的工作方式。它将为每个外部连接执行 1 个额外的查询。但是,这仍然比每次迭代执行 1 个查询少 lot。 documentation 说的很清楚了:
select_related works by creating an SQL join and including the fields of the related object in the SELECT statement. For this reason, select_related gets the related objects in the same database query. However, to avoid the much larger result set that would result from joining across a ‘many’ relationship, select_related is limited to single-valued relationships - foreign key and one-to-one.
prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using select_related, in addition to the foreign key and one-to-one relationships that are supported by select_related.
假设我们有 2 个外连接,总共有 1000 个匹配行:
- 没有prefetch_related的查询数:1 + 2*1000 = 2001
- prefetch_related 的查询数量:1 + 2 = 3
因此,不必担心每个连接的 1 个额外查询。