summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2025-06-03 22:34:39 -0400
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2025-06-04 10:48:13 +0200
commit3340d4144605bd150906d070ae3e910941fa83c9 (patch)
tree69108e27d670e24d1b9a95d9127bdac902cc1fa8
parent0c548e62d0166c559ca59845079c2b70730fcfe7 (diff)
[5.2.x] Fixed #36432 -- Fixed a prefetch_related crash on related target subclass queryset.
Regression in 626d77e52a3f247358514bcf51c761283968099c. Refs #36116. Thanks Cornelis Poppema for the excellent report. Backport of 08187c94ed02c45ad40a32244dedeaa7ac71ca87 from main.
-rw-r--r--django/db/models/fields/related_descriptors.py5
-rw-r--r--docs/releases/5.2.2.txt4
-rw-r--r--tests/prefetch_related/models.py4
-rw-r--r--tests/prefetch_related/tests.py13
4 files changed, 25 insertions, 1 deletions
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index f0b93e1366..6ef47960dd 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -183,8 +183,11 @@ class ForwardManyToOneDescriptor:
rel_obj_attr = self.field.get_foreign_related_value
instance_attr = self.field.get_local_related_value
instances_dict = {instance_attr(inst): inst for inst in instances}
- related_fields = self.field.foreign_related_fields
remote_field = self.field.remote_field
+ related_fields = [
+ queryset.query.resolve_ref(field.name).target
+ for field in self.field.foreign_related_fields
+ ]
queryset = queryset.filter(
TupleIn(
ColPairs(
diff --git a/docs/releases/5.2.2.txt b/docs/releases/5.2.2.txt
index 1a363ad55d..56efb69bfb 100644
--- a/docs/releases/5.2.2.txt
+++ b/docs/releases/5.2.2.txt
@@ -43,3 +43,7 @@ Bugfixes
<django.http.HttpRequest.get_preferred_type>` did not account for media type
parameters in ``Accept`` headers, reducing specificity in content negotiation
(:ticket:`36411`).
+
+* Fixed a regression in Django 5.2 that caused a crash when using
+ ``QuerySet.prefetch_related()`` to prefetch a foreign key with a ``Prefetch``
+ queryset for a subclass of the foreign target (:ticket:`36432`).
diff --git a/tests/prefetch_related/models.py b/tests/prefetch_related/models.py
index 2f37cde1c8..888485e169 100644
--- a/tests/prefetch_related/models.py
+++ b/tests/prefetch_related/models.py
@@ -271,6 +271,10 @@ class Employee(models.Model):
ordering = ["id"]
+class SelfDirectedEmployee(Employee):
+ pass
+
+
# Ticket #19607
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index b3531cc36f..3c0b5f4505 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -39,6 +39,7 @@ from .models import (
Qualification,
Reader,
Room,
+ SelfDirectedEmployee,
TaggedItem,
Teacher,
WordEntry,
@@ -435,6 +436,18 @@ class PrefetchRelatedTests(TestDataMixin, TestCase):
authors[1].active_favorite_authors, [self.author3, self.author4]
)
+ def test_prefetch_queryset_child_class(self):
+ employee = SelfDirectedEmployee.objects.create(name="Foo")
+ employee.boss = employee
+ employee.save()
+ with self.assertNumQueries(2):
+ retrieved_employee = SelfDirectedEmployee.objects.prefetch_related(
+ Prefetch("boss", SelfDirectedEmployee.objects.all())
+ ).get()
+ with self.assertNumQueries(0):
+ self.assertEqual(retrieved_employee, employee)
+ self.assertEqual(retrieved_employee.boss, retrieved_employee)
+
class RawQuerySetTests(TestDataMixin, TestCase):
def test_basic(self):