diff --git a/django/utils/tree.py b/django/utils/tree.py index cb45c7ee29..302cd37d5f 100644 --- a/django/utils/tree.py +++ b/django/utils/tree.py @@ -5,6 +5,8 @@ ORM. import copy +from django.utils.hashable import make_hashable + class Node: """ @@ -71,10 +73,7 @@ class Node: ) def __hash__(self): - return hash((self.__class__, self.connector, self.negated, *[ - tuple(child) if isinstance(child, list) else child - for child in self.children - ])) + return hash((self.__class__, self.connector, self.negated, *make_hashable(self.children))) def add(self, data, conn_type, squash=True): """ diff --git a/docs/releases/2.1.3.txt b/docs/releases/2.1.3.txt index 5de73d93d4..15e53db65b 100644 --- a/docs/releases/2.1.3.txt +++ b/docs/releases/2.1.3.txt @@ -4,9 +4,10 @@ Django 2.1.3 release notes *Expected November 1, 2018* -Django 2.1.3 fixes several bugs in 2.1.2 +Django 2.1.3 fixes several bugs in 2.1.2. Bugfixes ======== -* ... \ No newline at end of file +* Fixed a regression in Django 2.0 where combining ``Q`` objects with ``__in`` + lookups and lists crashed (:ticket:`29838`). diff --git a/tests/utils_tests/test_tree.py b/tests/utils_tests/test_tree.py index c59398aedb..154678ff57 100644 --- a/tests/utils_tests/test_tree.py +++ b/tests/utils_tests/test_tree.py @@ -24,12 +24,15 @@ class NodeTests(unittest.TestCase): node4 = Node(self.node1_children, connector='OTHER') node5 = Node(self.node1_children) node6 = Node([['a', 1], ['b', 2]]) + node7 = Node([('a', [1, 2])]) + node8 = Node([('a', (1, 2))]) self.assertNotEqual(hash(self.node1), hash(self.node2)) self.assertNotEqual(hash(self.node1), hash(node3)) self.assertNotEqual(hash(self.node1), hash(node4)) self.assertEqual(hash(self.node1), hash(node5)) self.assertEqual(hash(self.node1), hash(node6)) self.assertEqual(hash(self.node2), hash(Node())) + self.assertEqual(hash(node7), hash(node8)) def test_len(self): self.assertEqual(len(self.node1), 2)