summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2018-02-28 18:05:23 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2018-02-28 18:10:58 +0100
commit10a20e4b37da94fd55b4e9a13e634c2a379bd9e0 (patch)
tree8111399ad92b845594388ddfc1cf1bee735e9cb4
parentc50b9c33f0ba65ea79f890558be0f5b3cd7e2984 (diff)
[2.0.x] Fixed #29166 -- Fixed crash in When() expression with a list argument.
Thanks Matthew Pava for the report and Tim Graham and Carlton Gibson for reviews. Regression in 19b2dfd1bfe7fd716dd3d8bfa5f972070d83b42f. Backport of 54f80430be4a9adf1fc00b4ca17547415fafc69b from master
-rw-r--r--django/db/models/expressions.py10
-rw-r--r--docs/releases/2.0.3.txt3
-rw-r--r--tests/expressions_case/tests.py18
3 files changed, 27 insertions, 4 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 5470a357cf..43023b67fb 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -381,10 +381,12 @@ class BaseExpression:
def __hash__(self):
path, args, kwargs = self.deconstruct()
- h = hash(path) ^ hash(args)
- for kwarg in kwargs.items():
- h ^= hash(kwarg)
- return h
+ kwargs = kwargs.copy()
+ output_field = type(kwargs.pop('output_field', None))
+ return hash((path, output_field) + args + tuple([
+ (key, tuple(value)) if isinstance(value, list) else (key, value)
+ for key, value in kwargs.items()
+ ]))
class Expression(BaseExpression, Combinable):
diff --git a/docs/releases/2.0.3.txt b/docs/releases/2.0.3.txt
index c0c9ebb782..348af75bc0 100644
--- a/docs/releases/2.0.3.txt
+++ b/docs/releases/2.0.3.txt
@@ -21,3 +21,6 @@ Bugfixes
* Made ``Q.deconstruct()`` deterministic with multiple keyword arguments
(:ticket:`29125`). You may need to modify ``Q``'s in existing migrations, or
accept an autogenerated migration.
+
+* Fixed a regression where a ``When()`` expression with a list argument crashes
+ (:ticket:`29166`).
diff --git a/tests/expressions_case/tests.py b/tests/expressions_case/tests.py
index 090607e8b8..256be935ef 100644
--- a/tests/expressions_case/tests.py
+++ b/tests/expressions_case/tests.py
@@ -1293,3 +1293,21 @@ class CaseDocumentationExamples(TestCase):
[('Jack Black', 'P')],
transform=attrgetter('name', 'account_type')
)
+
+ def test_hash(self):
+ expression_1 = Case(
+ When(account_type__in=[Client.REGULAR, Client.GOLD], then=1),
+ default=2,
+ output_field=models.IntegerField(),
+ )
+ expression_2 = Case(
+ When(account_type__in=(Client.REGULAR, Client.GOLD), then=1),
+ default=2,
+ output_field=models.IntegerField(),
+ )
+ expression_3 = Case(When(account_type__in=[Client.REGULAR, Client.GOLD], then=1), default=2)
+ expression_4 = Case(When(account_type__in=[Client.PLATINUM, Client.GOLD], then=2), default=1)
+ self.assertEqual(hash(expression_1), hash(expression_2))
+ self.assertNotEqual(hash(expression_2), hash(expression_3))
+ self.assertNotEqual(hash(expression_1), hash(expression_4))
+ self.assertNotEqual(hash(expression_3), hash(expression_4))