Fixed #26196 -- Made sure __in lookups use to_field as default.
Thanks Simon Charette for the test.
This commit is contained in:
parent
04e13c8913
commit
46ecfb9b3a
|
@ -210,7 +210,7 @@ class BaseExpression(object):
|
||||||
])
|
])
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def _prepare(self):
|
def _prepare(self, field):
|
||||||
"""
|
"""
|
||||||
Hook used by Field.get_prep_lookup() to do custom preparation.
|
Hook used by Field.get_prep_lookup() to do custom preparation.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -740,7 +740,7 @@ class Field(RegisterLookupMixin):
|
||||||
Perform preliminary non-db specific lookup checks and conversions
|
Perform preliminary non-db specific lookup checks and conversions
|
||||||
"""
|
"""
|
||||||
if hasattr(value, '_prepare'):
|
if hasattr(value, '_prepare'):
|
||||||
return value._prepare()
|
return value._prepare(self)
|
||||||
|
|
||||||
if lookup_type in {
|
if lookup_type in {
|
||||||
'iexact', 'contains', 'icontains',
|
'iexact', 'contains', 'icontains',
|
||||||
|
|
|
@ -1108,12 +1108,18 @@ class QuerySet(object):
|
||||||
for field, objects in other._known_related_objects.items():
|
for field, objects in other._known_related_objects.items():
|
||||||
self._known_related_objects.setdefault(field, {}).update(objects)
|
self._known_related_objects.setdefault(field, {}).update(objects)
|
||||||
|
|
||||||
def _prepare(self):
|
def _prepare(self, field):
|
||||||
if self._fields is not None:
|
if self._fields is not None:
|
||||||
# values() queryset can only be used as nested queries
|
# values() queryset can only be used as nested queries
|
||||||
# if they are set up to select only a single field.
|
# if they are set up to select only a single field.
|
||||||
if len(self._fields or self.model._meta.concrete_fields) > 1:
|
if len(self._fields or self.model._meta.concrete_fields) > 1:
|
||||||
raise TypeError('Cannot use multi-field values as a filter value.')
|
raise TypeError('Cannot use multi-field values as a filter value.')
|
||||||
|
else:
|
||||||
|
# If the query is used as a subquery for a ForeignKey with non-pk
|
||||||
|
# target field, make sure to select the target field in the subquery.
|
||||||
|
foreign_fields = getattr(field, 'foreign_related_fields', ())
|
||||||
|
if len(foreign_fields) == 1 and not foreign_fields[0].primary_key:
|
||||||
|
return self.values(foreign_fields[0].name)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _as_sql(self, connection):
|
def _as_sql(self, connection):
|
||||||
|
|
|
@ -235,7 +235,7 @@ class Query(object):
|
||||||
memo[id(self)] = result
|
memo[id(self)] = result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _prepare(self):
|
def _prepare(self, field):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def get_compiler(self, using=None, connection=None):
|
def get_compiler(self, using=None, connection=None):
|
||||||
|
|
|
@ -21,3 +21,6 @@ Bugfixes
|
||||||
* Fixed a regression for cases where
|
* Fixed a regression for cases where
|
||||||
``ForeignObject.get_extra_descriptor_filter()`` returned a ``Q`` object
|
``ForeignObject.get_extra_descriptor_filter()`` returned a ``Q`` object
|
||||||
(:ticket:`26153`).
|
(:ticket:`26153`).
|
||||||
|
|
||||||
|
* Fixed regression with an ``__in=qs`` lookup for a ``ForeignKey`` with
|
||||||
|
``to_field`` set (:ticket:`26196`).
|
||||||
|
|
|
@ -2416,6 +2416,18 @@ class ToFieldTests(TestCase):
|
||||||
{lunch, dinner},
|
{lunch, dinner},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_in_subquery(self):
|
||||||
|
apple = Food.objects.create(name="apple")
|
||||||
|
lunch = Eaten.objects.create(food=apple, meal="lunch")
|
||||||
|
self.assertEqual(
|
||||||
|
set(Eaten.objects.filter(food__in=Food.objects.filter(name='apple'))),
|
||||||
|
{lunch}
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
set(Eaten.objects.filter(food__in=Food.objects.filter(name='apple').values('eaten__meal'))),
|
||||||
|
set()
|
||||||
|
)
|
||||||
|
|
||||||
def test_reverse_in(self):
|
def test_reverse_in(self):
|
||||||
apple = Food.objects.create(name="apple")
|
apple = Food.objects.create(name="apple")
|
||||||
pear = Food.objects.create(name="pear")
|
pear = Food.objects.create(name="pear")
|
||||||
|
|
Loading…
Reference in New Issue