[3.2.x] Fixed #32717 -- Fixed filtering of querysets combined with the | operator.

Address a long standing bug in a Where.add optimization to discard
equal nodes that was surfaced by implementing equality for Lookup
instances in bbf141bcdc.

Thanks Shaheed Haque for the report.

Backport of b81c7562fc from main
This commit is contained in:
Simon Charette 2021-05-11 01:19:44 -04:00 committed by Mariusz Felisiak
parent d6b6eda4ed
commit 386caa5445
4 changed files with 13 additions and 1 deletions

View File

@ -90,7 +90,7 @@ class Node:
If `squash` is False the data is prepared and added as a child to
this tree without further logic.
"""
if data in self.children:
if self.connector == conn_type and data in self.children:
return data
if not squash:
self.children.append(data)

View File

@ -10,3 +10,6 @@ Bugfixes
========
* Prepared for ``mysqlclient`` > 2.0.3 support (:ticket:`32732`).
* Fixed a regression in Django 3.2 that caused the incorrect filtering of
querysets combined with the ``|`` operator (:ticket:`32717`).

View File

@ -1338,6 +1338,10 @@ class Queries4Tests(TestCase):
self.assertEqual(len(combined), 1)
self.assertEqual(combined[0].name, 'a1')
def test_combine_or_filter_reuse(self):
combined = Author.objects.filter(name='a1') | Author.objects.filter(name='a3')
self.assertEqual(combined.get(name='a1'), self.a1)
def test_join_reuse_order(self):
# Join aliases are reused in order. This shouldn't raise AssertionError
# because change_map contains a circular reference (#26522).

View File

@ -57,6 +57,11 @@ class NodeTests(unittest.TestCase):
self.assertEqual(len(self.node1) + 1, len(node3))
self.assertEqual(str(node3), "(DEFAULT: ('a', 1), ('b', 2), ('c', 3))")
def test_add_eq_child_mixed_connector(self):
node = Node(['a', 'b'], 'OR')
self.assertEqual(node.add('a', 'AND'), 'a')
self.assertEqual(node, Node([Node(['a', 'b'], 'OR'), 'a'], 'AND'))
def test_negate(self):
# negated is False by default
self.assertFalse(self.node1.negated)