为什么django的prefetch_related()仅适用于all()而不是filter()? [英] Why does django's prefetch_related() only work with all() and not filter()?

查看:128
本文介绍了为什么django的prefetch_related()仅适用于all()而不是filter()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有这个模型:

  class PhotoAlbum(models.Model):
title = models.CharField (max_length = 128)
author = models.CharField(max_length = 128)

类照片(models.Model):
album = models.ForeignKey('PhotoAlbum')
format = models.IntegerField()

现在,如果我想看一下照片的一部分在专辑的一个子集有效率。我做这样的事情:

  someAlbums = PhotoAlbum.objects.filter(author =Davey Jones)prefetch_related( photo_set)
for someAlbums:
somePhotos = a.photo_set.all()

这只有两个查询,这是我期望的(一个获得相册,然后一个像SELECT * IN照片,其中photoalbum_id IN()。



但是,如果我这样做:

  someAlbums = PhotoAlbum.objects.filter(author =Davey Jones)。prefetch_related(photo_set)
for someAlbums:
somePhotos = a.photo_set.filter(format = 1)

然后它执行大量查询, WHERE format = 1 !我做错了什么,或者django不够聪明,意识到它已经获取了所有的照片,并可以在python中过滤它们?我发誓我在文档中读到应该做的那个...

解决方案

在Django 1.6及更早版本中,无法避免额外的查询。 prefetch_related 调用有效地缓存了查询器中每个专辑的 a.photoset.all()的结果。但是, a.photoset.filter(format = 1)是一个不同的查询器,因此您将为每个专辑生成一个额外的查询。



这在 prefetch_related 文档。 filter(format = 1)相当于 filter(spicy = True)



请注意,您可以通过过滤python中的照片来减少数量或查询:

  someAlbums = PhotoAlbum.objects.filter(author =Davey Jones)。prefetch_related(photo_set)
for someAlbums:
somePhotos = [p for a in a。 photoset.all()如果p.format == 1]

在Django 1.7中, a href =https://docs.djangoproject.com/en/1.7/ref/models/queries/#django.db.models.Prefetch =noreferrer> Prefetch() 对象,允许您控制 prefetch_related 的行为。

  from django.db.models import Prefetch 

someAlbums = PhotoAlbum.objects.filter(author =Davey Jones)。prefetch_related(
Prefetch(
photo_set,
queryset = Photo.objects.filter(format = 1),
to_attr =some_photos


for someAlbums:
somePhotos = a.some_photos

有关如何使用 Prefetch 对象的更多示例,请参阅 prefetch_related docs。


suppose I have this model:

class PhotoAlbum(models.Model):
    title = models.CharField(max_length=128)
    author = models.CharField(max_length=128)

class Photo(models.Model):
    album = models.ForeignKey('PhotoAlbum')
    format = models.IntegerField()

Now if I want to look at a subset of photos in a subset of albums efficiently. I do it something like this:

someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set")
for a in someAlbums:
    somePhotos = a.photo_set.all()

This does only two queries, which is what I expect (one to get the albums, and then one like `SELECT * IN photos WHERE photoalbum_id IN ().

Everything is great.

But if I do this:

someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set")
for a in someAlbums:
    somePhotos = a.photo_set.filter(format=1)

Then it does a ton of queries with WHERE format = 1! Am I doing something wrong or is django not smart enough to realise it has already fetched all the photos and can filter them in python? I swear I read somewhere in the documentation that it is supposed to do that...

解决方案

In Django 1.6 and earlier, it is not possible to avoid the extra queries. The prefetch_related call effectively caches the results of a.photoset.all() for every album in the queryset. However, a.photoset.filter(format=1) is a different queryset, so you will generate an extra query for every album.

This is explained in the prefetch_related docs. The filter(format=1) is equivalent to filter(spicy=True).

Note that you could reduce the number or queries by filtering the photos in python instead:

someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set")
for a in someAlbums:
    somePhotos = [p for p in a.photoset.all() if p.format == 1]

In Django 1.7, there is a Prefetch() object that allows you to control the behaviour of prefetch_related.

from django.db.models import Prefetch

someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related(
    Prefetch(
        "photo_set",
        queryset=Photo.objects.filter(format=1),
        to_attr="some_photos"
    )
)
for a in someAlbums:
    somePhotos = a.some_photos

For more examples of how to use the Prefetch object, see the prefetch_related docs.

这篇关于为什么django的prefetch_related()仅适用于all()而不是filter()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆