Fixed #23396 -- Ensured ValueQuerySets are not checked by check_related_objects.
This commit is contained in:
parent
3a34e45fdb
commit
0e16c3e3cd
@ -1052,6 +1052,15 @@ class QuerySet(object):
|
|||||||
"""
|
"""
|
||||||
return self.query.has_filters()
|
return self.query.has_filters()
|
||||||
|
|
||||||
|
def is_compatible_query_object_type(self, opts):
|
||||||
|
model = self.model
|
||||||
|
return (
|
||||||
|
model == opts.concrete_model or
|
||||||
|
opts.concrete_model in model._meta.get_parent_list() or
|
||||||
|
model in opts.get_parent_list()
|
||||||
|
)
|
||||||
|
is_compatible_query_object_type.queryset_only = True
|
||||||
|
|
||||||
|
|
||||||
class InstanceCheckMeta(type):
|
class InstanceCheckMeta(type):
|
||||||
def __instancecheck__(self, instance):
|
def __instancecheck__(self, instance):
|
||||||
@ -1209,6 +1218,13 @@ class ValuesQuerySet(QuerySet):
|
|||||||
% self.__class__.__name__)
|
% self.__class__.__name__)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def is_compatible_query_object_type(self, opts):
|
||||||
|
"""
|
||||||
|
ValueQuerySets do not need to be checked for compatibility.
|
||||||
|
We trust that users of ValueQuerySets know what they are doing.
|
||||||
|
"""
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class ValuesListQuerySet(ValuesQuerySet):
|
class ValuesListQuerySet(ValuesQuerySet):
|
||||||
def iterator(self):
|
def iterator(self):
|
||||||
|
@ -1094,21 +1094,17 @@ class Query(object):
|
|||||||
Checks the type of object passed to query relations.
|
Checks the type of object passed to query relations.
|
||||||
"""
|
"""
|
||||||
if field.rel:
|
if field.rel:
|
||||||
# testing for iterable of models
|
# QuerySets implement is_compatible_query_object_type() to
|
||||||
if hasattr(value, '__iter__'):
|
# determine compatibility with the given field.
|
||||||
# Check if the iterable has a model attribute, if so
|
if hasattr(value, 'is_compatible_query_object_type'):
|
||||||
# it is likely something like a QuerySet.
|
if not value.is_compatible_query_object_type(opts):
|
||||||
if hasattr(value, 'model') and hasattr(value.model, '_meta'):
|
raise ValueError(
|
||||||
model = value.model
|
'Cannot use QuerySet for "%s": Use a QuerySet for "%s".' %
|
||||||
if not (model == opts.concrete_model
|
(value.model._meta.model_name, opts.object_name)
|
||||||
or opts.concrete_model in model._meta.get_parent_list()
|
)
|
||||||
or model in opts.get_parent_list()):
|
elif hasattr(value, '__iter__'):
|
||||||
raise ValueError(
|
for v in value:
|
||||||
'Cannot use QuerySet for "%s": Use a QuerySet for "%s".' %
|
self.check_query_object_type(v, opts)
|
||||||
(model._meta.model_name, opts.object_name))
|
|
||||||
else:
|
|
||||||
for v in value:
|
|
||||||
self.check_query_object_type(v, opts)
|
|
||||||
else:
|
else:
|
||||||
# expecting single model instance here
|
# expecting single model instance here
|
||||||
self.check_query_object_type(value, opts)
|
self.check_query_object_type(value, opts)
|
||||||
|
@ -3487,6 +3487,14 @@ class RelatedLookupTypeTests(TestCase):
|
|||||||
with self.assertNumQueries(0):
|
with self.assertNumQueries(0):
|
||||||
ObjectB.objects.filter(objecta__in=ObjectA.objects.all())
|
ObjectB.objects.filter(objecta__in=ObjectA.objects.all())
|
||||||
|
|
||||||
|
def test_values_queryset_lookup(self):
|
||||||
|
"""
|
||||||
|
#23396 - Ensure ValueQuerySets are not checked for compatibility with the lookup field
|
||||||
|
"""
|
||||||
|
self.assertQuerysetEqual(ObjectB.objects.filter(
|
||||||
|
objecta__in=ObjectB.objects.all().values_list('pk')
|
||||||
|
).order_by('pk'), ['<ObjectB: ob>', '<ObjectB: pob>'])
|
||||||
|
|
||||||
|
|
||||||
class Ticket14056Tests(TestCase):
|
class Ticket14056Tests(TestCase):
|
||||||
def test_ticket_14056(self):
|
def test_ticket_14056(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user