假设我有这个模型:
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()
现在,如果我想高效地查看相册中的一部分照片。我这样做是这样的:
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set") for a in someAlbums: somePhotos = a.photo_set.all()
这只会执行两个查询,这正是我所期望的(一个查询得到相册,然后一个查询,例如“ SELECT * IN photos WHERE photoalbum_id IN()”。
一切都很棒。
但是,如果我这样做:
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set") for a in someAlbums: somePhotos = a.photo_set.filter(format=1)
然后用WHERE format = 1!进行大量查询!我是在做错什么,还是django不够聪明,以至于它已经获取了所有照片并可以在python中过滤它们?我发誓我在文档中的某个地方读到了应该做的…
WHERE format = 1
在Django 1.6和更早版本中,无法避免多余的查询。该prefetch_related调用有效地缓存了a.photoset.all()查询集中每个专辑的搜索结果。但是,这a.photoset.filter(format=1)是一个不同的查询集,因此你将为每个专辑生成一个额外的查询。
prefetch_related
a.photoset.all()
a.photoset.filter(format=1)
这在prefetch_related文档中进行了解释 。在filter(format=1)相当于filter(spicy=True)。
filter(format=1)
filter(spicy=True)
请注意,你可以改为使用python过滤照片来减少数量或查询:
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set") for a in someAlbums: somePhotos = [p for p in a.photo_set.all() if p.format == 1]
在Django 1.7中,有一个Prefetch()对象可让你控制的行为prefetch_related。
Prefetch()
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
有关如何使用该Prefetch对象的更多示例,请参阅prefetch_related文档。