summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/models/fields/related_lookups.py11
-rw-r--r--docs/releases/1.9.7.txt3
-rw-r--r--tests/one_to_one/models.py6
-rw-r--r--tests/one_to_one/tests.py10
4 files changed, 22 insertions, 8 deletions
diff --git a/django/db/models/fields/related_lookups.py b/django/db/models/fields/related_lookups.py
index 3123e94073..5454031c2a 100644
--- a/django/db/models/fields/related_lookups.py
+++ b/django/db/models/fields/related_lookups.py
@@ -24,15 +24,16 @@ def get_normalized_value(value, lhs):
from django.db.models import Model
if isinstance(value, Model):
value_list = []
- # A case like Restaurant.objects.filter(place=restaurant_instance),
- # where place is a OneToOneField and the primary key of Restaurant.
- if getattr(lhs.output_field, 'primary_key', False):
- return (value.pk,)
sources = lhs.output_field.get_path_info()[-1].target_fields
for source in sources:
while not isinstance(value, source.model) and source.remote_field:
source = source.remote_field.model._meta.get_field(source.remote_field.field_name)
- value_list.append(getattr(value, source.attname))
+ try:
+ value_list.append(getattr(value, source.attname))
+ except AttributeError:
+ # A case like Restaurant.objects.filter(place=restaurant_instance),
+ # where place is a OneToOneField and the primary key of Restaurant.
+ return (value.pk,)
return tuple(value_list)
if not isinstance(value, tuple):
return (value,)
diff --git a/docs/releases/1.9.7.txt b/docs/releases/1.9.7.txt
index 514d83bf15..a61f4ed9dd 100644
--- a/docs/releases/1.9.7.txt
+++ b/docs/releases/1.9.7.txt
@@ -26,3 +26,6 @@ Bugfixes
* Fixed ``dbshell`` crash on PostgreSQL with an empty database name
(:ticket:`26698`).
+
+* Fixed a regression in queries on a ``OneToOneField`` that has ``to_field``
+ and ``primary_key=True`` (:ticket:`26667`).
diff --git a/tests/one_to_one/models.py b/tests/one_to_one/models.py
index 2742fb186e..0f4aa70f6c 100644
--- a/tests/one_to_one/models.py
+++ b/tests/one_to_one/models.py
@@ -83,7 +83,7 @@ class MultiModel(models.Model):
class Target(models.Model):
- name = models.CharField(max_length=50)
+ name = models.CharField(max_length=50, unique=True)
class Pointer(models.Model):
@@ -98,6 +98,10 @@ class HiddenPointer(models.Model):
target = models.OneToOneField(Target, models.CASCADE, related_name='hidden+')
+class ToFieldPointer(models.Model):
+ target = models.OneToOneField(Target, models.CASCADE, to_field='name', primary_key=True)
+
+
# Test related objects visibility.
class SchoolManager(models.Manager):
def get_queryset(self):
diff --git a/tests/one_to_one/tests.py b/tests/one_to_one/tests.py
index 7e8c9c5dc3..2cb6568221 100644
--- a/tests/one_to_one/tests.py
+++ b/tests/one_to_one/tests.py
@@ -6,8 +6,8 @@ from django.utils.deprecation import RemovedInDjango20Warning
from .models import (
Bar, Director, Favorites, HiddenPointer, ManualPrimaryKey, MultiModel,
- Place, Pointer, RelatedModel, Restaurant, School, Target, UndergroundBar,
- Waiter,
+ Place, Pointer, RelatedModel, Restaurant, School, Target, ToFieldPointer,
+ UndergroundBar, Waiter,
)
@@ -530,3 +530,9 @@ class OneToOneTests(TestCase):
r = Restaurant.objects.first()
r2 = Restaurant.objects.filter(pk__exact=r).first()
self.assertEqual(r, r2)
+
+ def test_primary_key_to_field_filter(self):
+ target = Target.objects.create(name='foo')
+ pointer = ToFieldPointer.objects.create(target=target)
+ self.assertQuerysetEqual(ToFieldPointer.objects.filter(target=target), [pointer], lambda x: x)
+ self.assertQuerysetEqual(ToFieldPointer.objects.filter(pk__exact=pointer), [pointer], lambda x: x)