summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRan Benita <ran234@gmail.com>2017-12-23 11:35:08 +0200
committerTim Graham <timograham@gmail.com>2017-12-26 12:18:39 -0500
commit4e4619a2b8f79699fbdb2c4f1bc4db55f59af6e6 (patch)
tree58c72a678e7247df8d293310d509e26a4cc8d5a9
parent830636df739d359116e3106c35375ac838bf15c3 (diff)
[2.0.x] Fixed #28944 -- Fixed crash when chaining values()/values_list() after QuerySet.select_for_update(of=()).
Backport of c21f158295d92e35caf96436bfdbbff554fc5569 from master
-rw-r--r--django/db/models/sql/compiler.py17
-rw-r--r--docs/releases/2.0.1.txt3
-rw-r--r--tests/select_for_update/tests.py22
3 files changed, 34 insertions, 8 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 279aa7a00f..839e37aa8a 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -190,7 +190,7 @@ class SQLCompiler:
"AS alias" for the column (possibly None).
The klass_info structure contains the following information:
- - Which model to instantiate
+ - The base model of the query.
- Which columns for that model are present in the query (by
position of the select clause).
- related_klass_infos: [f, klass_info] to descent into
@@ -207,20 +207,21 @@ class SQLCompiler:
select_idx += 1
assert not (self.query.select and self.query.default_cols)
if self.query.default_cols:
+ cols = self.get_default_columns()
+ else:
+ # self.query.select is a special case. These columns never go to
+ # any model.
+ cols = self.query.select
+ if cols:
select_list = []
- for c in self.get_default_columns():
+ for col in cols:
select_list.append(select_idx)
- select.append((c, None))
+ select.append((col, None))
select_idx += 1
klass_info = {
'model': self.query.model,
'select_fields': select_list,
}
- # self.query.select is a special case. These columns never go to
- # any model.
- for col in self.query.select:
- select.append((col, None))
- select_idx += 1
for alias, annotation in self.query.annotation_select.items():
annotations[alias] = select_idx
select.append((annotation, alias))
diff --git a/docs/releases/2.0.1.txt b/docs/releases/2.0.1.txt
index ccbc7c29a3..97260ef5b8 100644
--- a/docs/releases/2.0.1.txt
+++ b/docs/releases/2.0.1.txt
@@ -37,3 +37,6 @@ Bugfixes
* Fixed crash on SQLite when renaming a field in a model referenced by a
``ManyToManyField`` (:ticket:`28884`).
+
+* Fixed a crash when chaining ``values()`` or ``values_list()`` after
+ ``QuerySet.select_for_update(of=(...))`` (:ticket:`28944`).
diff --git a/tests/select_for_update/tests.py b/tests/select_for_update/tests.py
index 6de268cb2b..a750dc61db 100644
--- a/tests/select_for_update/tests.py
+++ b/tests/select_for_update/tests.py
@@ -120,6 +120,28 @@ class SelectForUpdateTests(TransactionTestCase):
expected = [value.upper() for value in expected]
self.assertTrue(self.has_for_update_sql(ctx.captured_queries, of=expected))
+ @skipUnlessDBFeature('has_select_for_update_of')
+ def test_for_update_of_followed_by_values(self):
+ with transaction.atomic():
+ values = list(Person.objects.select_for_update(of=('self',)).values('pk'))
+ self.assertEqual(values, [{'pk': self.person.pk}])
+
+ @skipUnlessDBFeature('has_select_for_update_of')
+ def test_for_update_of_followed_by_values_list(self):
+ with transaction.atomic():
+ values = list(Person.objects.select_for_update(of=('self',)).values_list('pk'))
+ self.assertEqual(values, [(self.person.pk,)])
+
+ @skipUnlessDBFeature('has_select_for_update_of')
+ def test_for_update_of_self_when_self_is_not_selected(self):
+ """
+ select_for_update(of=['self']) when the only columns selected are from
+ related tables.
+ """
+ with transaction.atomic():
+ values = list(Person.objects.select_related('born').select_for_update(of=('self',)).values('born__name'))
+ self.assertEqual(values, [{'born__name': self.city1.name}])
+
@skipUnlessDBFeature('has_select_for_update_nowait')
def test_nowait_raises_error_on_block(self):
"""