Opened 3 years ago
Closed 3 years ago
#33730 closed Bug (invalid)
FilteredRelation join duplicated when referenced in multiple filter statements
Reported by: | Ben Nace | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 3.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Given the following models
class Grandparent(models.Model): tag = models.CharField(max_length=100) enabled = models.BooleanField(default=True) class Parent(models.Model): tag = models.CharField(max_length=100) grandparent = models.ForeignKey(Grandparent, on_delete=models.CASCADE) class Child(models.Model): tag = models.CharField(max_length=100) parents = models.ManyToManyField(Parent)
When doing the following query with a filtered relation and a single filter statement, the SQL is generated as expected:
Child.objects.alias(a_parents=FilteredRelation('parents', condition=Q(tag='a'))).filter(a_parents__grandparent__enabled=True, a_parents__grandparent__tag='x')
SELECT "test_app_child"."id", "test_app_child"."tag" FROM "test_app_child" INNER JOIN "test_app_child_parents" ON ("test_app_child"."id" = "test_app_child_parents"."child_id") INNER JOIN "test_app_parent" a_parents ON ("test_app_child_parents"."parent_id" = a_parents."id" AND ("test_app_child"."tag" = 'a')) INNER JOIN "test_app_grandparent" ON (a_parents."grandparent_id" = "test_app_grandparent"."id") WHERE ("test_app_grandparent"."enabled" AND "test_app_grandparent"."tag" = 'x')
However, when the filter conditions are split across multiple calls to the filter function, say from them being applied in different functions, the joins for the filtered relation get duplicated in the SQL.
Child.objects.alias(a_parents=FilteredRelation('parents', condition=Q(tag='a'))).filter(a_parents__isnull=False).filter(a_parents__grandparent__tag='x')
SELECT "test_app_child"."id", "test_app_child"."tag" FROM "test_app_child" INNER JOIN "test_app_child_parents" ON ("test_app_child"."id" = "test_app_child_parents"."child_id") INNER JOIN "test_app_parent" a_parents ON ("test_app_child_parents"."parent_id" = a_parents."id" AND ("test_app_child"."tag" = 'a')) INNER JOIN "test_app_child_parents" T4 ON ("test_app_child"."id" = T4."child_id") INNER JOIN "test_app_parent" T5 ON (T4."parent_id" = T5."id" AND ("test_app_child"."tag" = 'a')) INNER JOIN "test_app_grandparent" ON (T5."grandparent_id" = "test_app_grandparent"."id") WHERE (a_parents."id" IS NOT NULL AND "test_app_grandparent"."tag" = 'x')
Note:
See TracTickets
for help on using tickets.
This is expected
filter(A, B)
andfilter(A).filter(B)
don't behave the same when multi-valued relationships are involved as documented.