From 5cda1d27027ea74d8a1b53e43bef697cd4426e9a Mon Sep 17 00:00:00 2001 From: Alexey Voronov Date: Sun, 22 Dec 2013 00:03:17 +0200 Subject: [PATCH] [1.6.x] Fixed #21643 -- repeated execution of qs with F() + timedelta Thanks Tim Graham for review and Tai Lee for the additional test to prove this was a regression in 1.6. Backport of 7f2485b4d1 and 8137215973 from master --- django/db/models/sql/expressions.py | 1 + docs/releases/1.6.3.txt | 4 ++++ tests/expressions_regress/tests.py | 14 ++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/django/db/models/sql/expressions.py b/django/db/models/sql/expressions.py index 62adf79d877..31e089925d2 100644 --- a/django/db/models/sql/expressions.py +++ b/django/db/models/sql/expressions.py @@ -108,6 +108,7 @@ class SQLEvaluator(object): def evaluate_date_modifier_node(self, node, qn, connection): timedelta = node.children.pop() sql, params = self.evaluate_node(node, qn, connection) + node.children.append(timedelta) if timedelta.days == 0 and timedelta.seconds == 0 and \ timedelta.microseconds == 0: diff --git a/docs/releases/1.6.3.txt b/docs/releases/1.6.3.txt index 99b8566270e..a8b63dc72ae 100644 --- a/docs/releases/1.6.3.txt +++ b/docs/releases/1.6.3.txt @@ -14,3 +14,7 @@ several bugs in 1.6.2: * Fixed ``AttributeError`` when using :meth:`~django.db.models.query.QuerySet.bulk_create` with ``ForeignObject`` (`#21566 `_). + +* Fixed crash of ``QuerySet``\s that use ``F() + timedelta()`` when their query + was compiled more once + (`#21643 `_). diff --git a/tests/expressions_regress/tests.py b/tests/expressions_regress/tests.py index ddb2c83b4f1..a9737f433d0 100644 --- a/tests/expressions_regress/tests.py +++ b/tests/expressions_regress/tests.py @@ -259,6 +259,20 @@ class FTimeDeltaTests(TestCase): self.days_long.append(e4.completed-e4.assigned) self.expnames = [e.name for e in Experiment.objects.all()] + def test_multiple_query_compilation(self): + # Ticket #21643 + queryset = Experiment.objects.filter(end__lt=F('start') + datetime.timedelta(hours=1)) + q1 = str(queryset.query) + q2 = str(queryset.query) + self.assertEqual(q1, q2) + + def test_query_clone(self): + # Ticket #21643 + qs = Experiment.objects.filter(end__lt=F('start') + datetime.timedelta(hours=1)) + qs2 = qs.all() + list(qs) + list(qs2) + def test_delta_add(self): for i in range(len(self.deltas)): delta = self.deltas[i]