From 0393b9262dcf1b8302d35a8a470e14837ca1300b Mon Sep 17 00:00:00 2001 From: Takayuki Hirayama Date: Fri, 4 Jun 2021 00:32:55 +0900 Subject: [PATCH] Fixed #32812 -- Restored immutability of named values from QuerySet.values_list(). Regression in 981a072dd4dec586f8fc606712ed9a2ef116eeee. Thanks pirelle for the report. --- django/db/models/utils.py | 6 +++++- docs/releases/3.2.5.txt | 4 +++- tests/model_utils/__init__.py | 0 tests/model_utils/tests.py | 10 ++++++++++ tests/prefetch_related/tests.py | 7 +++++++ 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 tests/model_utils/__init__.py create mode 100644 tests/model_utils/tests.py diff --git a/django/db/models/utils.py b/django/db/models/utils.py index 764ca5888b..a8bd20fba7 100644 --- a/django/db/models/utils.py +++ b/django/db/models/utils.py @@ -45,4 +45,8 @@ def create_namedtuple_class(*names): def __reduce__(self): return unpickle_named_row, (names, tuple(self)) - return type('Row', (namedtuple('Row', names),), {'__reduce__': __reduce__}) + return type( + 'Row', + (namedtuple('Row', names),), + {'__reduce__': __reduce__, '__slots__': ()}, + ) diff --git a/docs/releases/3.2.5.txt b/docs/releases/3.2.5.txt index f7b1d1e87b..b782985ca1 100644 --- a/docs/releases/3.2.5.txt +++ b/docs/releases/3.2.5.txt @@ -9,4 +9,6 @@ Django 3.2.5 fixes several bugs in 3.2.4. Bugfixes ======== -* ... +* Fixed a regression in Django 3.2 that caused a crash of + ``QuerySet.values_list(…, named=True)`` after ``prefetch_related()`` + (:ticket:`32812`). diff --git a/tests/model_utils/__init__.py b/tests/model_utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/model_utils/tests.py b/tests/model_utils/tests.py new file mode 100644 index 0000000000..be4dd4300b --- /dev/null +++ b/tests/model_utils/tests.py @@ -0,0 +1,10 @@ +from django.db.models.utils import create_namedtuple_class +from django.test import SimpleTestCase + + +class NamedTupleClassTests(SimpleTestCase): + def test_immutability(self): + row_class = create_namedtuple_class('field1', 'field2') + row = row_class('value1', 'value2') + with self.assertRaises(AttributeError): + row.field3 = 'value3' diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py index e21bd5ec23..cba1897fc5 100644 --- a/tests/prefetch_related/tests.py +++ b/tests/prefetch_related/tests.py @@ -309,6 +309,13 @@ class PrefetchRelatedTests(TestDataMixin, TestCase): list(Book.objects.prefetch_related(relation)) self.assertEqual(add_q_mock.call_count, 1) + def test_named_values_list(self): + qs = Author.objects.prefetch_related('books') + self.assertCountEqual( + [value.name for value in qs.values_list('name', named=True)], + ['Anne', 'Charlotte', 'Emily', 'Jane'], + ) + class RawQuerySetTests(TestDataMixin, TestCase): def test_basic(self):