Saya selalu berasumsi bahwa merangkai banyak pemanggilan filter () di Django selalu sama dengan mengumpulkannya dalam satu panggilan.
# Equivalent
Model.objects.filter(foo=1).filter(bar=2)
Model.objects.filter(foo=1,bar=2)
tetapi saya telah menemukan queryset yang rumit dalam kode saya di mana hal ini tidak terjadi
class Inventory(models.Model):
book = models.ForeignKey(Book)
class Profile(models.Model):
user = models.OneToOneField(auth.models.User)
vacation = models.BooleanField()
country = models.CharField(max_length=30)
# Not Equivalent!
Book.objects.filter(inventory__user__profile__vacation=False).filter(inventory__user__profile__country='BR')
Book.objects.filter(inventory__user__profile__vacation=False, inventory__user__profile__country='BR')
SQL yang dihasilkan adalah
SELECT "library_book"."id", "library_book"."asin", "library_book"."added", "library_book"."updated" FROM "library_book" INNER JOIN "library_inventory" ON ("library_book"."id" = "library_inventory"."book_id") INNER JOIN "auth_user" ON ("library_inventory"."user_id" = "auth_user"."id") INNER JOIN "library_profile" ON ("auth_user"."id" = "library_profile"."user_id") INNER JOIN "library_inventory" T5 ON ("library_book"."id" = T5."book_id") INNER JOIN "auth_user" T6 ON (T5."user_id" = T6."id") INNER JOIN "library_profile" T7 ON (T6."id" = T7."user_id") WHERE ("library_profile"."vacation" = False AND T7."country" = BR )
SELECT "library_book"."id", "library_book"."asin", "library_book"."added", "library_book"."updated" FROM "library_book" INNER JOIN "library_inventory" ON ("library_book"."id" = "library_inventory"."book_id") INNER JOIN "auth_user" ON ("library_inventory"."user_id" = "auth_user"."id") INNER JOIN "library_profile" ON ("auth_user"."id" = "library_profile"."user_id") WHERE ("library_profile"."vacation" = False AND "library_profile"."country" = BR )
Queryset pertama dengan filter()
panggilan berantai bergabung dengan model Inventory dua kali secara efektif membuat OR antara dua kondisi sedangkan queryset kedua AND menyatukan kedua kondisi tersebut. Saya berharap bahwa kueri pertama juga akan DAN dua ketentuan. Apakah ini perilaku yang diharapkan atau apakah ini bug di Django?
Jawaban untuk pertanyaan terkait Apakah ada kerugian menggunakan ".filter (). Filter (). Filter () ..." di Django? tampaknya menunjukkan bahwa dua queryset harus setara.
sumber
further restrict
berarti begituless restrictive
?Kedua gaya pemfilteran ini setara dalam banyak kasus, tetapi ketika kueri pada objek berbasis ForeignKey atau ManyToManyField, keduanya sedikit berbeda.
Contoh dari dokumentasi .
model
Blog to Entry adalah relasi one-to-many.
objek
Dengan asumsi ada beberapa objek blog dan entri di sini.
pertanyaan
Untuk kueri pertama (filter tunggal satu), hanya cocok dengan blog1.
Untuk kueri kedua (filter berantai satu), filter ini menyaring blog1 dan blog2.
Filter pertama membatasi queryset ke blog1, blog2 dan blog5; filter kedua membatasi kumpulan blog lebih jauh ke blog1 dan blog2.
Dan Anda harus menyadari itu
Jadi, tidak sama, karena Blog dan Entri adalah hubungan yang memiliki banyak nilai.
Referensi: https://docs.djangoproject.com/en/1.8/topics/db/queries/#spanning-multi-valued-relationships
Jika ada yang salah, tolong perbaiki saya.
Edit: Mengubah v1.6 menjadi v1.8 karena link 1.6 tidak lagi tersedia.
sumber
Seperti yang Anda lihat dalam pernyataan SQL yang dihasilkan, perbedaannya bukanlah "ATAU" seperti yang diduga beberapa orang. Ini adalah bagaimana WHERE dan JOIN ditempatkan.
Example1 (tabel gabungan yang sama):
(contoh dari https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships )
Ini akan memberi Anda semua Blog yang memiliki satu entri dengan keduanya (entry_ headline _contains = 'Lennon') AND (entry__pub_date__year = 2008), yang Anda harapkan dari kueri ini. Hasil: Buku dengan {entry.headline: 'Life of Lennon', entry.pub_date: '2008'}
Contoh 2 (dirantai)
Ini akan mencakup semua hasil dari Contoh 1, tetapi akan menghasilkan hasil yang sedikit lebih banyak. Karena ini pertama-tama menyaring semua blog dengan (entry_ headline _contains = 'Lennon') dan kemudian dari filter hasil (entry__pub_date__year = 2008).
Perbedaannya adalah ini juga akan memberi Anda hasil seperti: Book with {entry.headline: ' Lennon ', entry.pub_date: 2000}, {entry.headline: 'Bill', entry.pub_date: 2008 }
Dalam kasus Anda
Saya pikir inilah yang Anda butuhkan:
Dan jika Anda ingin menggunakan ATAU silakan baca: https://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects
sumber
Terkadang Anda tidak ingin menggabungkan beberapa filter bersama seperti ini:
Dan kode berikut sebenarnya tidak mengembalikan hal yang benar.
Yang dapat Anda lakukan sekarang adalah menggunakan filter hitungan anotasi.
Dalam hal ini kami menghitung semua shift yang termasuk dalam peristiwa tertentu.
Setelah itu Anda dapat memfilter berdasarkan anotasi.
Solusi ini juga lebih murah pada queryset besar.
Semoga ini membantu.
sumber