From 4540842bc385a60cf32970a8b372b80d47704bca Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Mon, 9 Dec 2019 12:55:12 +0100 Subject: [PATCH] Fixed #31044 -- Errored nicely when using Prefetch with a raw() queryset. --- django/db/models/query.py | 11 +++++++++-- tests/prefetch_related/tests.py | 8 +++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/django/db/models/query.py b/django/db/models/query.py index 73991df7bbb..764d3ea2892 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -1534,8 +1534,15 @@ class Prefetch: self.prefetch_through = lookup # `prefetch_to` is the path to the attribute that stores the result. self.prefetch_to = lookup - if queryset is not None and not issubclass(queryset._iterable_class, ModelIterable): - raise ValueError('Prefetch querysets cannot use values().') + if queryset is not None and ( + isinstance(queryset, RawQuerySet) or ( + hasattr(queryset, '_iterable_class') and + not issubclass(queryset._iterable_class, ModelIterable) + ) + ): + raise ValueError( + 'Prefetch querysets cannot use raw() and values().' + ) if to_attr: self.prefetch_to = LOOKUP_SEP.join(lookup.split(LOOKUP_SEP)[:-1] + [to_attr]) diff --git a/tests/prefetch_related/tests.py b/tests/prefetch_related/tests.py index 5b944a456ba..35c2a1c6b87 100644 --- a/tests/prefetch_related/tests.py +++ b/tests/prefetch_related/tests.py @@ -815,12 +815,18 @@ class CustomPrefetchTests(TestCase): self.traverse_qs(list(houses), [['occupants', 'houses', 'main_room']]) def test_values_queryset(self): - with self.assertRaisesMessage(ValueError, 'Prefetch querysets cannot use values().'): + msg = 'Prefetch querysets cannot use raw() and values().' + with self.assertRaisesMessage(ValueError, msg): Prefetch('houses', House.objects.values('pk')) # That error doesn't affect managers with custom ModelIterable subclasses self.assertIs(Teacher.objects_custom.all()._iterable_class, ModelIterableSubclass) Prefetch('teachers', Teacher.objects_custom.all()) + def test_raw_queryset(self): + msg = 'Prefetch querysets cannot use raw() and values().' + with self.assertRaisesMessage(ValueError, msg): + Prefetch('houses', House.objects.raw('select pk from house')) + def test_to_attr_doesnt_cache_through_attr_as_list(self): house = House.objects.prefetch_related( Prefetch('rooms', queryset=Room.objects.all(), to_attr='to_rooms'),