Loading django/db/models/query.py +6 −1 Original line number Diff line number Diff line Loading @@ -1538,7 +1538,12 @@ def prefetch_one_level(instances, prefetcher, lookup, level): # contains some prefetch_related lookups. We don't want to trigger the # prefetch_related functionality by evaluating the query. Rather, we need # to merge in the prefetch_related lookups. additional_lookups = getattr(rel_qs, '_prefetch_related_lookups', []) # Copy the lookups in case it is a Prefetch object which could be reused # later (happens in nested prefetch_related). additional_lookups = [ copy.copy(additional_lookup) for additional_lookup in getattr(rel_qs, '_prefetch_related_lookups', []) ] if additional_lookups: # Don't need to clone because the manager should have given us a fresh # instance, so we access an internal instead of using public interface Loading tests/prefetch_related/tests.py +11 −0 Original line number Diff line number Diff line Loading @@ -626,6 +626,17 @@ class CustomPrefetchTests(TestCase): room = Room.objects.filter(main_room_of__isnull=False).prefetch_related(Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist'), to_attr='main_room_of_attr')).first() self.assertIsNone(room.main_room_of_attr) def test_nested_prefetch_related_are_not_overwritten(self): # Regression test for #24873 houses_2 = House.objects.prefetch_related(Prefetch('rooms')) persons = Person.objects.prefetch_related(Prefetch('houses', queryset=houses_2)) houses = House.objects.prefetch_related(Prefetch('occupants', queryset=persons)) list(houses) # queryset must be evaluated once to reproduce the bug. self.assertEqual( houses.all()[0].occupants.all()[0].houses.all()[1].rooms.all()[0], self.room2_1 ) class DefaultManagerTests(TestCase): Loading Loading
django/db/models/query.py +6 −1 Original line number Diff line number Diff line Loading @@ -1538,7 +1538,12 @@ def prefetch_one_level(instances, prefetcher, lookup, level): # contains some prefetch_related lookups. We don't want to trigger the # prefetch_related functionality by evaluating the query. Rather, we need # to merge in the prefetch_related lookups. additional_lookups = getattr(rel_qs, '_prefetch_related_lookups', []) # Copy the lookups in case it is a Prefetch object which could be reused # later (happens in nested prefetch_related). additional_lookups = [ copy.copy(additional_lookup) for additional_lookup in getattr(rel_qs, '_prefetch_related_lookups', []) ] if additional_lookups: # Don't need to clone because the manager should have given us a fresh # instance, so we access an internal instead of using public interface Loading
tests/prefetch_related/tests.py +11 −0 Original line number Diff line number Diff line Loading @@ -626,6 +626,17 @@ class CustomPrefetchTests(TestCase): room = Room.objects.filter(main_room_of__isnull=False).prefetch_related(Prefetch('main_room_of', queryset=houses.filter(address='DoesNotExist'), to_attr='main_room_of_attr')).first() self.assertIsNone(room.main_room_of_attr) def test_nested_prefetch_related_are_not_overwritten(self): # Regression test for #24873 houses_2 = House.objects.prefetch_related(Prefetch('rooms')) persons = Person.objects.prefetch_related(Prefetch('houses', queryset=houses_2)) houses = House.objects.prefetch_related(Prefetch('occupants', queryset=persons)) list(houses) # queryset must be evaluated once to reproduce the bug. self.assertEqual( houses.all()[0].occupants.all()[0].houses.all()[1].rooms.all()[0], self.room2_1 ) class DefaultManagerTests(TestCase): Loading