[1.10.x] Fixed #26667 -- Fixed a regression in queries on a OneToOneField that has to_field and primary_key=True.
Thanks Simon Charette for review.
Backport of e2296e7f0a
from master
This commit is contained in:
parent
27983d82c2
commit
8996054cb4
|
@ -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,)
|
||||
|
|
|
@ -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`).
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue