summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--django/db/models/fields/related_descriptors.py5
-rw-r--r--tests/prefetch_related/tests.py26
3 files changed, 30 insertions, 2 deletions
diff --git a/AUTHORS b/AUTHORS
index 3ca8ad40f5..77053c9568 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -423,6 +423,7 @@ answer newbie questions, and generally made Django that much better:
James Timmins <jameshtimmins@gmail.com>
James Turk <dev@jamesturk.net>
James Wheare <django@sparemint.com>
+ Jamie Matthews <jamie@mtth.org>
Jannis Leidel <jannis@leidel.info>
Janos Guljas
Jan Pazdziora
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index d5aa968400..9c50ef16ce 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -646,8 +646,9 @@ def create_reverse_many_to_one_manager(superclass, rel):
# Since we just bypassed this class' get_queryset(), we must manage
# the reverse relation manually.
for rel_obj in queryset:
- instance = instances_dict[rel_obj_attr(rel_obj)]
- setattr(rel_obj, self.field.name, instance)
+ if not self.field.is_cached(rel_obj):
+ instance = instances_dict[rel_obj_attr(rel_obj)]
+ setattr(rel_obj, self.field.name, instance)
cache_name = self.field.remote_field.get_cache_name()
return queryset, rel_obj_attr, instance_attr, False, cache_name, False
diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py
index 4ea7fccd5e..5040f3d886 100644
--- a/tests/prefetch_related/tests.py
+++ b/tests/prefetch_related/tests.py
@@ -1614,3 +1614,29 @@ class ReadPrefetchedObjectsCacheTests(TestCase):
with self.assertNumQueries(4):
# AuthorWithAge -> Author -> FavoriteAuthors, Book
self.assertSequenceEqual(authors, [self.author1, self.author2])
+
+
+class NestedPrefetchTests(TestCase):
+ @classmethod
+ def setUpTestData(cls):
+ house = House.objects.create(name='Big house', address='123 Main St')
+ cls.room = Room.objects.create(name='Kitchen', house=house)
+
+ def test_nested_prefetch_is_not_overwritten_by_related_object(self):
+ """
+ The prefetched relationship is used rather than populating the reverse
+ relationship from the parent, when prefetching a set of child objects
+ related to a set of parent objects and the child queryset itself
+ specifies a prefetch back to the parent.
+ """
+ queryset = House.objects.only('name').prefetch_related(
+ Prefetch('rooms', queryset=Room.objects.prefetch_related(
+ Prefetch('house', queryset=House.objects.only('address')),
+ )),
+ )
+ with self.assertNumQueries(3):
+ house = queryset.first()
+
+ self.assertIs(Room.house.is_cached(self.room), True)
+ with self.assertNumQueries(0):
+ house.rooms.first().house.address