Tim*_*mmm 81 django orm filter prefetch
假设我有这个模型:
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()
Run Code Online (Sandbox Code Playgroud)
现在,如果我想有效地查看相册子集中的一部分照片.我这样做:
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set")
for a in someAlbums:
somePhotos = a.photo_set.all()
Run Code Online (Sandbox Code Playgroud)
这只做了两个查询,这是我所期望的(一个是获得专辑,然后是一个像`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)
Run Code Online (Sandbox Code Playgroud)
然后它做了大量的查询WHERE format = 1
!我做错了什么或django不够聪明,意识到它已经取出所有的照片并可以在python中过滤它们?我发誓我在文档中的某个地方读到它本应该这样做......
Ala*_*air 150
在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 a in someAlbums:
somePhotos = [p for p in a.photo_set.all() if p.format == 1]
Run Code Online (Sandbox Code Playgroud)
在Django 1.7中,有一个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 a in someAlbums:
somePhotos = a.some_photos
Run Code Online (Sandbox Code Playgroud)
有关如何使用该Prefetch
对象的更多示例,请参阅prefetch_related
文档.
来自文档:
...与QuerySets一样,任何暗示不同数据库查询的后续链接方法都将忽略先前缓存的结果,并使用新的数据库查询检索数据.所以,如果你写下面的内容:
pizzas = Pizza.objects.prefetch_related('toppings')
[list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]
...那么pizza.toppings.all()已被预取的事实对你没有帮助 - 事实上它会伤害性能,因为你已经完成了一个你没有使用过的数据库查询.所以请谨慎使用此功能!
在您的情况下,"a.photo_set.filter(format = 1)"被视为新查询.
此外,"photo_set"是反向查找 - 通过不同的管理器完全实现.
归档时间: |
|
查看次数: |
57690 次 |
最近记录: |