diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 89fba2b56a..a590f2796e 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1104,8 +1104,19 @@ class Query(object): if field.rel: # testing for iterable of models if hasattr(value, '__iter__'): - for v in value: - self.check_query_object_type(v, opts) + # Check if the iterable has a model attribute, if so + # it is likely something like a QuerySet. + if hasattr(value, 'model') and hasattr(value.model, '_meta'): + model = value.model + if not (model == opts.concrete_model + or opts.concrete_model in model._meta.get_parent_list() + or model in opts.get_parent_list()): + raise ValueError( + 'Cannot use QuerySet for "%s": Use a QuerySet for "%s".' % + (model._meta.model_name, opts.object_name)) + else: + for v in value: + self.check_query_object_type(v, opts) else: # expecting single model instance here self.check_query_object_type(value, opts) diff --git a/tests/queries/tests.py b/tests/queries/tests.py index 380d64b8f9..e7dd7fab74 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -3461,6 +3461,10 @@ class RelatedLookupTypeTests(TestCase): # parent objects self.assertQuerysetEqual(ObjectC.objects.exclude(childobjecta=self.oa), out_c) + # Test for #23226 + with self.assertNumQueries(0): + ObjectB.objects.filter(objecta__in=ObjectA.objects.all()) + class Ticket14056Tests(TestCase): def test_ticket_14056(self):