From 8aea6b802ced18a54f00db71c53e09c643f7514c Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Tue, 14 Jan 2025 06:18:30 +0100 Subject: [5.2.x] Fixed #35677 -- Avoided non-sticky filtering of prefetched many-to-many. The original queryset._next_is_sticky() call never had the intended effect as no further filtering was applied internally after the pk__in lookup making it a noop. In order to be coherent with how related filters are applied when retrieving objects from a related manager the effects of what calling _next_is_sticky() prior to applying annotations and filters to the queryset provided for prefetching are emulated by allowing the reuse of all pre-existing JOINs. Thanks David Glenck and Thiago Bellini Ribeiro for the detailed reports and tests. Backport of 2598b371a93e21d84b7a2a99b2329535c8c0c138 from main. --- django/db/models/sql/query.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'django/db/models/sql/query.py') diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index ddf6c891fa..ec47d9aa24 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1616,7 +1616,7 @@ class Query(BaseExpression): def add_filter(self, filter_lhs, filter_rhs): self.add_q(Q((filter_lhs, filter_rhs))) - def add_q(self, q_object): + def add_q(self, q_object, reuse_all=False): """ A preprocessor for the internal _add_q(). Responsible for doing final join promotion. @@ -1630,7 +1630,11 @@ class Query(BaseExpression): existing_inner = { a for a in self.alias_map if self.alias_map[a].join_type == INNER } - clause, _ = self._add_q(q_object, self.used_aliases) + if reuse_all: + can_reuse = set(self.alias_map) + else: + can_reuse = self.used_aliases + clause, _ = self._add_q(q_object, can_reuse) if clause: self.where.add(clause, AND) self.demote_joins(existing_inner) -- cgit v1.3