diff --git a/django/db/models/fields/related_lookups.py b/django/db/models/fields/related_lookups.py index 62bc92b6ff..39b8f6e941 100644 --- a/django/db/models/fields/related_lookups.py +++ b/django/db/models/fields/related_lookups.py @@ -81,7 +81,7 @@ class RelatedIn(In): AND) return root_constraint.as_sql(compiler, connection) else: - if getattr(self.rhs, '_forced_pk', False): + if not getattr(self.rhs, 'has_select_fields', True): self.rhs.clear_select_clause() if (getattr(self.lhs.output_field, 'primary_key', False) and self.lhs.output_field.model == self.rhs.model): diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py index c37fcabba4..48e68d0b8b 100644 --- a/django/db/models/lookups.py +++ b/django/db/models/lookups.py @@ -367,6 +367,9 @@ class In(FieldGetDbPrepValueIterableMixin, BuiltinLookup): placeholder = '(' + ', '.join(sqls) + ')' return (placeholder, sqls_params) else: + if not getattr(self.rhs, 'has_select_fields', True): + self.rhs.clear_select_clause() + self.rhs.add_fields(['pk']) return super().process_rhs(compiler, connection) def get_rhs_op(self, connection, rhs): diff --git a/django/db/models/query.py b/django/db/models/query.py index abb95ba74a..f266e2bf22 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -1100,15 +1100,12 @@ class QuerySet: self._known_related_objects.setdefault(field, {}).update(objects) def _prepare_as_filter_value(self): - if self._fields is None: - queryset = self.values('pk') - queryset.query._forced_pk = True - else: + if self._fields and len(self._fields) > 1: # values() queryset can only be used as nested queries # if they are set up to select only a single field. if len(self._fields) > 1: raise TypeError('Cannot use multi-field values as a filter value.') - queryset = self._clone() + queryset = self._clone() return queryset.query.as_subquery_filter(queryset._db) def _add_hints(self, **hints): diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 6bfd454080..8c3ed06040 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -214,6 +214,10 @@ class Query: self._annotations = OrderedDict() return self._annotations + @property + def has_select_fields(self): + return bool(self.select or self.annotation_select_mask or self.extra_select_mask) + def __str__(self): """ Return the query as a string of SQL with the parameter values @@ -326,7 +330,6 @@ class Query: if hasattr(obj, '_setup_query'): obj._setup_query() obj.context = self.context.copy() - obj._forced_pk = getattr(self, '_forced_pk', False) return obj def add_context(self, key, value): @@ -1060,10 +1063,7 @@ class Query: # opts would be Author's (from the author field) and value.model # would be Author.objects.all() queryset's .model (Author also). # The field is the related field on the lhs side. - # If _forced_pk isn't set, this isn't a queryset query or values() - # or values_list() was specified by the developer in which case - # that choice is trusted. - if (getattr(value, '_forced_pk', False) and + if (isinstance(value, Query) and not value.has_select_fields and not check_rel_lookup_compatibility(value.model, opts, field)): raise ValueError( 'Cannot use QuerySet for "%s": Use a QuerySet for "%s".' %