leo*_*ews 5 python django query-optimization django-queryset
我有一个Django视图,我正在尝试优化.它显示页面上的父对象列表及其子对象.子模型将外键返回到父项,因此select_related似乎不适用.
class Parent(models.Model):
name = models.CharField(max_length=31)
class Child(models.Model):
name = models.CharField(max_length=31)
parent = models.ForeignKey(Parent)
Run Code Online (Sandbox Code Playgroud)
一个简单的实现使用n + 1个查询,其中n是父对象的数量,即.一个查询用于获取父列表,然后一个查询用于获取每个父项的子项.
我写了一个视图,在两个查询中完成工作 - 一个用于获取父对象,另一个用于获取相关的子对象,然后是一些Python(我太尴尬了,无法在此处发布)将它们全部重新组合在一起.
一旦我发现自己导入标准库的collections模块,我意识到我可能做错了.可能有一个更简单的方法,但我缺乏Django经验来找到它.任何指针将非常感谢!
related_name在外键中添加a ,然后使用prefetch_relatedDjango 1.4中添加的方法:
返回 ,
QuerySet它将在单个批次中自动检索每个指定查找的相关对象。这与 具有相似的目的
select_related,因为两者都旨在阻止因访问相关对象而导致的数据库查询的泛滥,但策略却截然不同:
select_related通过创建 SQL 连接并在语句中包含相关对象的字段来工作SELECT。因此,select_related在同一个数据库查询中获取相关对象。然而,为了避免通过“多”关系加入而产生更大的结果集,select_related仅限于单值关系 - 外键和一对一。
prefetch_related另一方面,对每个关系进行单独的查找,并在 Python 中进行“连接”。这使得它能够预取多对多和多对一对象,这是使用 无法完成的select_related,此外还有 所支持的外键和一对一关系select_related。它还支持预取GenericRelation和GenericForeignKey。
class Parent(models.Model):
name = models.CharField(max_length=31)
class Child(models.Model):
name = models.CharField(max_length=31)
parent = models.ForeignKey(Parent, related_name='children')
>>> Parent.objects.all().prefetch_related('children')
Run Code Online (Sandbox Code Playgroud)
所有相关子项都将在单个查询中获取,并用于创建具有相关结果的预填充缓存的查询集。然后在调用中使用这些查询集self.children.all()
。
注意 1,与 QuerySet 一样,任何暗示不同数据库查询的后续链接方法将忽略先前缓存的结果,并使用新的数据库查询检索数据。
注意 2,如果您用来
iterator()运行查询,prefetch_related()调用将被忽略,因为这两个优化一起没有意义。