【问题标题】:Django prefetch_related query not working as required, troubleshooting neededDjango prefetch_related 查询未按要求工作,需要进行故障排除
【发布时间】:2016-05-02 00:21:06
【问题描述】:

我有两个简单的 Django 模型:

class PhotoStream(models.Model):
    cover = models.ForeignKey('links.Photo')
    creation_time = models.DateTimeField(auto_now_add=True)

class Photo(models.Model):
    owner = models.ForeignKey(User)
    which_stream = models.ManyToManyField(PhotoStream)
    image_file = models.ImageField(upload_to=upload_photo_to_location, storage=OverwriteStorage())

目前我拥有的唯一数据是 6 张照片,它们都属于 1 个照片流。在形成照片流查询集时,我正在尝试以下方法来预取所有相关照片:

queryset = PhotoStream.objects.order_by('-creation_time').prefetch_related('photo_set')
for obj in queryset:
    print obj.photo_set.all() 
#print connection.queries

通过调试工具栏检查,我发现如果我删除语句的prefetch_related 部分,上面的查询数量完全相同。它显然不起作用。我也试过prefetch_related('cover') - 这也不起作用。

谁能指出我做错了什么,以及如何解决?我的目标是获取查询集中每个照片流的所有相关照片。我怎么可能做到这一点?


在运行 for 循环后打印 connection.queries 包括:

SELECT ("links_photo_which_stream"."photostream_id") AS "_prefetch_related_val", "links_photo"."id", "links_photo"."owner_id", "links_photo"."image_file" FROM "links_photo" INNER JOIN "links_photo_which_stream" ON ("links_photo"."id" = "links_photo_which_stream"."photo_id") WHERE "links_photo_which_stream"."photostream_id" IN (1)

注意:我已经简化了问题中发布的模型,因此上面的查询不包括一些实际出现在输出中但与此问题无关的字段。

【问题讨论】:

  • 你能发布正在生成的查询吗?
  • @solarissmoke:添加
  • 谢谢。你能看到其他查询中的每张照片是单独获取的吗?
  • 你在which_stream 关系中有through 表吗?
  • @GwynBleidD:是的,我愿意,因为这是一个 m-2-m 关系。

标签: django django-models django-views django-queryset


【解决方案1】:

以下是prefetch_related的部分摘录:

另一方面,**prefetch_related** 对每个关系进行单独查找,并在 Python 中执行 ‘joining’

还有更多:

>>> Pizza.objects.all().prefetch_related('toppings')

这意味着每个披萨都有一个self.toppings.all();现在每次调用 self.toppings.all() 时,它不必去数据库中查找项目,而是会在单个查询中填充的 预取 QuerySet 缓存中找到它们。

因此,您看到的查询数量将始终相同,但如果您使用 prefetch_related,那么它不会为每个 photostream 访问数据库,而是会访问它所对应的 prefetched QuerySet cache已经构建并从那里获取photo_set

【讨论】:

  • 我不确定我理解你的意思。您可以测量在这两种情况下查询时所花费的总时间,但为此您需要有一些重要的数据。 prefetch_related 将为您做的是将往返行程保存到数据库本身。
  • 我特别指的是客观测量到数据库的往返行程确实被保存的任何方式(因为 SQL 查询计数不会改变,就像你解释的那样)。我怎么知道我实施的实际工作?
  • 您可以查看查询本身(以及将其发布在您的问题中)该查询的内容类似于 prefetch_related_val
  • 运行for循环后需要打印connection.queries。你可以使用from django.db import connection获取connection
  • 感谢您的帮助。添加了问题的摘录(检查)。 prefetch_related_val 似乎在那里。我想这结束了这个问题?我会接受你的回答。
猜你喜欢
  • 2017-02-18
  • 1970-01-01
  • 1970-01-01
  • 2020-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-14
  • 2017-06-04
相关资源
最近更新 更多