summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnssi Kääriäinen <anssi.kaariainen@thl.fi>2016-02-11 08:39:37 +0200
committerTim Graham <timograham@gmail.com>2016-02-11 11:09:08 -0500
commit46ecfb9b3a11a360724e3375ba78c33c46d6a992 (patch)
tree29826ddb4ce88d420826d63025fab3c808733d24
parent04e13c89138d48c20e774a2b6bf06796f73ac0fe (diff)
Fixed #26196 -- Made sure __in lookups use to_field as default.
Thanks Simon Charette for the test.
-rw-r--r--django/db/models/expressions.py2
-rw-r--r--django/db/models/fields/__init__.py2
-rw-r--r--django/db/models/query.py8
-rw-r--r--django/db/models/sql/query.py2
-rw-r--r--docs/releases/1.9.3.txt3
-rw-r--r--tests/queries/tests.py12
6 files changed, 25 insertions, 4 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 203aabeff4..0f9c42009d 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -210,7 +210,7 @@ class BaseExpression(object):
])
return c
- def _prepare(self):
+ def _prepare(self, field):
"""
Hook used by Field.get_prep_lookup() to do custom preparation.
"""
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index e5c5ca74df..56ab438d75 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -740,7 +740,7 @@ class Field(RegisterLookupMixin):
Perform preliminary non-db specific lookup checks and conversions
"""
if hasattr(value, '_prepare'):
- return value._prepare()
+ return value._prepare(self)
if lookup_type in {
'iexact', 'contains', 'icontains',
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 5e2e5d7917..f37ed0f1b6 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1108,12 +1108,18 @@ class QuerySet(object):
for field, objects in other._known_related_objects.items():
self._known_related_objects.setdefault(field, {}).update(objects)
- def _prepare(self):
+ def _prepare(self, field):
if self._fields is not None:
# values() queryset can only be used as nested queries
# if they are set up to select only a single field.
if len(self._fields or self.model._meta.concrete_fields) > 1:
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
def _as_sql(self, connection):
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index f9df41392b..fb3529c2be 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -235,7 +235,7 @@ class Query(object):
memo[id(self)] = result
return result
- def _prepare(self):
+ def _prepare(self, field):
return self
def get_compiler(self, using=None, connection=None):
diff --git a/docs/releases/1.9.3.txt b/docs/releases/1.9.3.txt
index 61a92878c7..e6f200c864 100644
--- a/docs/releases/1.9.3.txt
+++ b/docs/releases/1.9.3.txt
@@ -21,3 +21,6 @@ Bugfixes
* Fixed a regression for cases where
``ForeignObject.get_extra_descriptor_filter()`` returned a ``Q`` object
(:ticket:`26153`).
+
+* Fixed regression with an ``__in=qs`` lookup for a ``ForeignKey`` with
+ ``to_field`` set (:ticket:`26196`).
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 91ff7bfc8d..e4cb420fda 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -2416,6 +2416,18 @@ class ToFieldTests(TestCase):
{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):
apple = Food.objects.create(name="apple")
pear = Food.objects.create(name="pear")