Skip to content

Commit

Permalink
Refs #32143 -- Removed superflous constraints on excluded query.
Browse files Browse the repository at this point in the history
The outer query reference is not necessary when alias can be reused and
can even be harmful by confusing query planers.

Refs #34597.
  • Loading branch information
charettes authored and felixxm committed Jun 14, 2023
1 parent cfc9c94 commit 1c4f5f3
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 5 deletions.
7 changes: 4 additions & 3 deletions django/db/models/sql/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -2020,10 +2020,11 @@ def split_exclude(self, filter_expr, can_reuse, names_with_path):
lookup = lookup_class(pk.get_col(query.select[0].alias), pk.get_col(alias))
query.where.add(lookup, AND)
query.external_aliases[alias] = True
else:
lookup_class = select_field.get_lookup("exact")
lookup = lookup_class(col, ResolvedOuterRef(trimmed_prefix))
query.where.add(lookup, AND)

lookup_class = select_field.get_lookup("exact")
lookup = lookup_class(col, ResolvedOuterRef(trimmed_prefix))
query.where.add(lookup, AND)
condition, needed_inner = self.build_filter(Exists(query))

if contains_louter:
Expand Down
13 changes: 11 additions & 2 deletions tests/queries/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3231,7 +3231,7 @@ def test_to_field(self):
[self.r2],
)

def test_ticket14511(self):
def test_exclude_m2m_through(self):
alex = Person.objects.get_or_create(name="Alex")[0]
jane = Person.objects.get_or_create(name="Jane")[0]

Expand Down Expand Up @@ -3267,7 +3267,16 @@ def employ(employer, employee, title):
.distinct()
.order_by("name")
)
self.assertSequenceEqual(alex_nontech_employers, [google, intel, microsoft])
with self.assertNumQueries(1) as ctx:
self.assertSequenceEqual(alex_nontech_employers, [google, intel, microsoft])
sql = ctx.captured_queries[0]["sql"]
# Company's ID should appear in SELECT and INNER JOIN, not in EXISTS as
# the outer query reference is not necessary when an alias is reused.
company_id = "%s.%s" % (
connection.ops.quote_name(Company._meta.db_table),
connection.ops.quote_name(Company._meta.get_field("id").column),
)
self.assertEqual(sql.count(company_id), 2)

def test_exclude_reverse_fk_field_ref(self):
tag = Tag.objects.create()
Expand Down

0 comments on commit 1c4f5f3

Please sign in to comment.