misalkan saya memiliki model ini:
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()
Sekarang jika saya ingin melihat subset foto dalam subset album secara efisien. Saya melakukannya seperti ini:
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set")
for a in someAlbums:
somePhotos = a.photo_set.all()
Ini hanya melakukan dua kueri, yang saya harapkan (satu untuk mendapatkan album, dan satu lagi seperti `SELECT * IN photos WHERE photoalbum_id IN ().
Semuanya bagus.
Tetapi jika saya melakukan ini:
someAlbums = PhotoAlbum.objects.filter(author="Davey Jones").prefetch_related("photo_set")
for a in someAlbums:
somePhotos = a.photo_set.filter(format=1)
Kemudian ia melakukan banyak pertanyaan dengan WHERE format = 1
! Apakah saya melakukan sesuatu yang salah atau apakah Django tidak cukup pintar untuk menyadari bahwa ia telah mengambil semua foto dan dapat memfilternya dengan python? Saya bersumpah saya membaca di suatu tempat di dokumentasi bahwa itu seharusnya melakukan itu ...
Jawaban:
Dalam Django 1.6 dan sebelumnya, tidaklah mungkin untuk menghindari kueri tambahan. The
prefetch_related
panggilan efektif cache hasila.photoset.all()
untuk setiap album di queryset tersebut. Namun,a.photoset.filter(format=1)
ini adalah kumpulan kueri yang berbeda, jadi Anda akan menghasilkan kueri tambahan untuk setiap album.Ini dijelaskan di
prefetch_related
dokumen. Thefilter(format=1)
setara denganfilter(spicy=True)
.Perhatikan bahwa Anda dapat mengurangi jumlah atau kueri dengan memfilter foto dengan python sebagai gantinya:
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]
Dalam Django 1.7, ada
Prefetch()
obyek yang mengijinkan anda untuk mengontrol perilakunyaprefetch_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
Untuk contoh lebih lanjut tentang bagaimana menggunakan
Prefetch
objek, lihatprefetch_related
dokumen.sumber
Dari dokumen :
Dalam kasus Anda, "a.photo_set.filter (format = 1)" diperlakukan seperti kueri baru.
Selain itu, "photo_set" adalah pencarian terbalik - yang diterapkan melalui pengelola yang berbeda sekaligus.
sumber
photo_set
dapat diambil sebelumnya, juga, dengan.prefetch_related('photo_set')
. Tapi ketertiban penting, seperti yang telah Anda jelaskan.Satu dapat digunakan
select_related
jika Anda ingin menggunakannya dengan filter ()results = Geography.objects.filter(state__pk = 1).select_related('country') results.query
Untuk selengkapnya: https://docs.djangoproject.com/en/3.1/ref/models/querysets/#select-related
sumber