J'ai toujours pensé que l'enchaînement de plusieurs appels à filter() dans Django était toujours la même chose que de les rassembler en un seul appel.
# Equivalent
Model.objects.filter(foo=1).filter(bar=2)
Model.objects.filter(foo=1,bar=2)
mais j'ai rencontré dans mon code un queryset compliqué où ce n'est pas le cas
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')
Le code SQL généré est le suivant
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 )
Le premier queryset avec le chaînage filter()
calls joint deux fois le modèle d'inventaire, créant ainsi un OU entre les deux conditions, tandis que le deuxième jeu de questions ET réunit les deux conditions. Je m'attendais à ce que la première requête fasse également un ET entre les deux conditions. S'agit-il du comportement attendu ou d'un bogue dans Django ?
La réponse à une question connexe Y a-t-il un inconvénient à utiliser ".filter().filter().filter()..." dans Django ? semble indiquer que les deux ensembles de questions devraient être équivalents.