浏览代码

Fixed #32812 -- Restored immutability of named values from QuerySet.values_list().

Regression in 981a072dd4dec586f8fc606712ed9a2ef116eeee.

Thanks pirelle for the report.
Takayuki Hirayama 3 年之前
父节点
当前提交
0393b9262d
共有 5 个文件被更改,包括 25 次插入2 次删除
  1. 5 1
      django/db/models/utils.py
  2. 3 1
      docs/releases/3.2.5.txt
  3. 0 0
      tests/model_utils/__init__.py
  4. 10 0
      tests/model_utils/tests.py
  5. 7 0
      tests/prefetch_related/tests.py

+ 5 - 1
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__': ()},
+    )

+ 3 - 1
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`).

+ 0 - 0
tests/model_utils/__init__.py


+ 10 - 0
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'

+ 7 - 0
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):