From 38eaf2f21a2398a8dd8444f6df3723898cb5fe2a Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Wed, 31 Jan 2024 16:10:05 +0100 Subject: [PATCH] Fixed #35159 -- Fixed dumpdata crash when base querysets use prefetch_related(). Regression in 139135627650ed6aaaf4c755b82c3bd43f2b8f51 following deprecation in edbf930287cb72e9afab1f7208c24b1146b0c4ec. Thanks Andrea F for the report. --- django/core/management/commands/dumpdata.py | 5 ++++- docs/releases/5.0.2.txt | 4 ++++ tests/fixtures/models.py | 6 ++++++ tests/fixtures/tests.py | 16 ++++++++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py index cc183517e302..01ff8974dd14 100644 --- a/django/core/management/commands/dumpdata.py +++ b/django/core/management/commands/dumpdata.py @@ -219,7 +219,10 @@ def get_objects(count_only=False): if count_only: yield queryset.order_by().count() else: - yield from queryset.iterator() + chunk_size = ( + 2000 if queryset._prefetch_related_lookups else None + ) + yield from queryset.iterator(chunk_size=chunk_size) try: self.stdout.ending = None diff --git a/docs/releases/5.0.2.txt b/docs/releases/5.0.2.txt index 8e2d648ecce8..83f1af7b4f00 100644 --- a/docs/releases/5.0.2.txt +++ b/docs/releases/5.0.2.txt @@ -24,3 +24,7 @@ Bugfixes ``FilteredRelation()`` with querysets as right-hand sides (:ticket:`35135`). ``FilteredRelation()`` now raises a ``ValueError`` on querysets as right-hand sides. + +* Fixed a regression in Django 5.0 that caused a crash of the ``dumpdata`` + management command when a base queryset used ``prefetch_related()`` + (:ticket:`35159`). diff --git a/tests/fixtures/models.py b/tests/fixtures/models.py index 37b0066d70c3..c87e170afc9d 100644 --- a/tests/fixtures/models.py +++ b/tests/fixtures/models.py @@ -101,9 +101,15 @@ class Meta: proxy = True +class VisaManager(models.Manager): + def get_queryset(self): + return super().get_queryset().prefetch_related("permissions") + + class Visa(models.Model): person = models.ForeignKey(Person, models.CASCADE) permissions = models.ManyToManyField(Permission, blank=True) + objects = VisaManager() def __str__(self): return "%s %s" % ( diff --git a/tests/fixtures/tests.py b/tests/fixtures/tests.py index 78141b25b430..bce55bc3554d 100644 --- a/tests/fixtures/tests.py +++ b/tests/fixtures/tests.py @@ -830,6 +830,22 @@ def test_dumpdata_proxy_with_concrete(self): ) self.assertEqual(len(warning_list), 0) + def test_dumpdata_objects_with_prefetch_related(self): + management.call_command( + "loaddata", "fixture6.json", "fixture8.json", verbosity=0 + ) + with self.assertNumQueries(5): + self._dumpdata_assert( + ["fixtures.visa"], + '[{"fields": {"permissions": [["add_user", "auth", "user"]],' + '"person": ["Stephane Grappelli"]},' + '"model": "fixtures.visa", "pk": 2},' + '{"fields": {"permissions": [], "person": ["Prince"]},' + '"model": "fixtures.visa", "pk": 3}]', + natural_foreign_keys=True, + primary_keys="2,3", + ) + def test_compress_format_loading(self): # Load fixture 4 (compressed), using format specification management.call_command("loaddata", "fixture4.json", verbosity=0)