1. 程式人生 > 其它 >表名小寫_set.all()再根據欄位過濾

表名小寫_set.all()再根據欄位過濾

orm - 為什麼django的prefetch_related()只能用於all()而不能用於filter()?

假設我有這個模型:

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中過濾它們? 我發誓我在文件中的某個地方讀到它本應該這樣做......

2個解決方案 142 votes

在Django 1.6及更早版本中,無法避免額外的查詢。 prefetch_related呼叫有效地快取了查詢集中每個專輯的filter(spicy=True)

的結果。 但是,a.photoset.filter(format=1)是一個不同的查詢集,因此您將為每個專輯生成一個額外的查詢。

這在prefetch_related文件中有解釋。 prefetch_related相當於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_related物件,允許您控制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
每天逼著自己寫點東西,終有一天會為自己的變化感動的。這是一個潛移默化的過程,每天堅持編編故事,自己不知不覺就會擁有故事人物的特質的。 Explicit is better than implicit.(清楚優於含糊)