mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +00:00 
			
		
		
		
	[2.0.x] Fixed #28944 -- Fixed crash when chaining values()/values_list() after QuerySet.select_for_update(of=()).
Backport of c21f158295 from master
			
			
This commit is contained in:
		| @@ -190,7 +190,7 @@ class SQLCompiler: | |||||||
|         "AS alias" for the column (possibly None). |         "AS alias" for the column (possibly None). | ||||||
|  |  | ||||||
|         The klass_info structure contains the following information: |         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 |         - Which columns for that model are present in the query (by | ||||||
|           position of the select clause). |           position of the select clause). | ||||||
|         - related_klass_infos: [f, klass_info] to descent into |         - related_klass_infos: [f, klass_info] to descent into | ||||||
| @@ -207,20 +207,21 @@ class SQLCompiler: | |||||||
|             select_idx += 1 |             select_idx += 1 | ||||||
|         assert not (self.query.select and self.query.default_cols) |         assert not (self.query.select and self.query.default_cols) | ||||||
|         if 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 = [] |             select_list = [] | ||||||
|             for c in self.get_default_columns(): |             for col in cols: | ||||||
|                 select_list.append(select_idx) |                 select_list.append(select_idx) | ||||||
|                 select.append((c, None)) |                 select.append((col, None)) | ||||||
|                 select_idx += 1 |                 select_idx += 1 | ||||||
|             klass_info = { |             klass_info = { | ||||||
|                 'model': self.query.model, |                 'model': self.query.model, | ||||||
|                 'select_fields': select_list, |                 '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(): |         for alias, annotation in self.query.annotation_select.items(): | ||||||
|             annotations[alias] = select_idx |             annotations[alias] = select_idx | ||||||
|             select.append((annotation, alias)) |             select.append((annotation, alias)) | ||||||
|   | |||||||
| @@ -37,3 +37,6 @@ Bugfixes | |||||||
|  |  | ||||||
| * Fixed crash on SQLite when renaming a field in a model referenced by a | * Fixed crash on SQLite when renaming a field in a model referenced by a | ||||||
|   ``ManyToManyField`` (:ticket:`28884`). |   ``ManyToManyField`` (:ticket:`28884`). | ||||||
|  |  | ||||||
|  | * Fixed a crash when chaining ``values()`` or ``values_list()`` after | ||||||
|  |   ``QuerySet.select_for_update(of=(...))`` (:ticket:`28944`). | ||||||
|   | |||||||
| @@ -120,6 +120,28 @@ class SelectForUpdateTests(TransactionTestCase): | |||||||
|             expected = [value.upper() for value in expected] |             expected = [value.upper() for value in expected] | ||||||
|         self.assertTrue(self.has_for_update_sql(ctx.captured_queries, of=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') |     @skipUnlessDBFeature('has_select_for_update_nowait') | ||||||
|     def test_nowait_raises_error_on_block(self): |     def test_nowait_raises_error_on_block(self): | ||||||
|         """ |         """ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user