Ich habe immer angenommen, dass das Verketten mehrerer filter () -Aufrufe in Django immer dasselbe ist wie das Sammeln in einem einzigen Aufruf.
# Equivalent
Model.objects.filter(foo=1).filter(bar=2)
Model.objects.filter(foo=1,bar=2)
Ich bin jedoch auf einen komplizierten Abfragesatz in meinem Code gestoßen, bei dem dies nicht der Fall ist
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')
Das generierte SQL ist
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 )
Das erste Abfrageset mit den verketteten filter()
Aufrufen verbindet das Inventarmodell zweimal und erstellt effektiv ein ODER zwischen den beiden Bedingungen, während das zweite Abfrageset die beiden Bedingungen UND-verknüpft. Ich hatte erwartet, dass die erste Abfrage auch UND die beiden Bedingungen würde. Ist dies das erwartete Verhalten oder ist dies ein Fehler in Django?
Die Antwort auf eine verwandte Frage Gibt es einen Nachteil bei der Verwendung von ".filter (). Filter (). Filter () ..." in Django? scheint darauf hinzudeuten, dass die beiden Abfragesätze gleichwertig sein sollten.
quelle
further restrict
Mittelless restrictive
?Diese beiden Filterstile sind in den meisten Fällen gleichwertig. Bei Abfragen von Objekten, die auf ForeignKey oder ManyToManyField basieren, unterscheiden sie sich jedoch geringfügig.
Beispiele aus der Dokumentation .
Modell
Blog to Entry ist eine Eins-zu-Viele-Beziehung.
Objekte
Angenommen, es gibt hier einige Blog- und Eintragsobjekte.
Anfragen
Bei der ersten Abfrage (Einzelfilter 1) stimmt sie nur mit blog1 überein.
Bei der zweiten Abfrage (verkettete Filter eins) werden blog1 und blog2 herausgefiltert.
Der erste Filter beschränkt das Abfrageset auf blog1, blog2 und blog5. Der zweite Filter beschränkt die Anzahl der Blogs weiter auf Blog1 und Blog2.
Und das solltest du erkennen
Es ist also nicht dasselbe, denn Blog und Eintrag sind mehrwertige Beziehungen.
Referenz: https://docs.djangoproject.com/de/1.8/topics/db/queries/#spanning-multi-valued-relationships
Wenn etwas nicht stimmt, korrigieren Sie mich bitte.
Bearbeiten: v1.6 in v1.8 geändert, da die 1.6-Links nicht mehr verfügbar sind.
quelle
Wie Sie in den generierten SQL-Anweisungen sehen können, ist der Unterschied nicht das "ODER", wie manche vermuten. So wird WHERE und JOIN platziert.
Beispiel 1 (gleiche verbundene Tabelle):
(Beispiel aus https://docs.djangoproject.com/de/dev/topics/db/queries/#spanning-multi-valued-relationships )
Dadurch erhalten Sie alle Blogs, die einen Eintrag mit sowohl (entry_ headline _contains = 'Lennon') als auch (entry__pub_date__year = 2008) haben, was Sie von dieser Abfrage erwarten würden. Ergebnis: Buchen Sie mit {entry.headline: 'Life of Lennon', entry.pub_date: '2008'}
Beispiel 2 (verkettet)
Dies deckt alle Ergebnisse aus Beispiel 1 ab, erzeugt jedoch etwas mehr Ergebnisse. Weil es zuerst alle Blogs mit (entry_ headline _contains = 'Lennon') und dann aus den Ergebnisfiltern (entry__pub_date__year = 2008) filtert.
Der Unterschied besteht darin, dass Sie auch folgende Ergebnisse erhalten: Buchen mit {entry.headline: ' Lennon ', entry.pub_date: 2000}, {entry.headline: 'Bill', entry.pub_date: 2008 }
In deinem Fall
Ich denke, es ist das, was du brauchst:
Und wenn Sie OR verwenden möchten, lesen Sie bitte: https://docs.djangoproject.com/de/dev/topics/db/queries/#complex-lookups-with-q-objects
quelle
Manchmal möchten Sie nicht mehrere Filter wie folgt zusammenfügen:
Und der folgende Code würde tatsächlich nicht das Richtige zurückgeben.
Was Sie jetzt tun können, ist die Verwendung eines Anmerkungszählungsfilters.
In diesem Fall zählen wir alle Schichten, die zu einem bestimmten Ereignis gehören.
Anschließend können Sie nach Anmerkungen filtern.
Diese Lösung ist auch bei großen Abfragesätzen günstiger.
Hoffe das hilft.
quelle