Fixed #28375 -- Fixed KeyError crash on reverse prefetch of a model with OneToOneField primary key to a non-pk field.

This commit is contained in:
Paulo 2017-08-14 17:27:25 -04:00 committed by Tim Graham
parent b5ad5c628a
commit fea9cb46aa
3 changed files with 25 additions and 8 deletions

View File

@ -63,8 +63,6 @@ and two directions (forward and reverse) for a total of six combinations.
``ReverseManyToManyDescriptor``, use ``ManyToManyDescriptor`` instead.
"""
from operator import attrgetter
from django.db import connections, router, transaction
from django.db.models import Q, signals
from django.db.models.query import QuerySet
@ -334,11 +332,8 @@ class ReverseOneToOneDescriptor:
queryset = self.get_queryset()
queryset._add_hints(instance=instances[0])
rel_obj_attr = attrgetter(self.related.field.attname)
def instance_attr(obj):
return obj.pk
rel_obj_attr = self.related.field.get_local_related_value
instance_attr = self.related.field.get_foreign_related_value
instances_dict = {instance_attr(inst): inst for inst in instances}
query = {'%s__in' % self.related.field.name: instances}
queryset = queryset.filter(**query)

View File

@ -65,7 +65,12 @@ class BookWithYear(Book):
class Bio(models.Model):
author = models.OneToOneField(Author, models.CASCADE)
author = models.OneToOneField(
Author,
models.CASCADE,
primary_key=True,
to_field='name',
)
books = models.ManyToManyField(Book, blank=True)

View File

@ -81,6 +81,23 @@ class PrefetchRelatedTests(TestCase):
with self.assertRaises(BookWithYear.DoesNotExist):
book.bookwithyear
def test_onetoone_reverse_with_to_field_pk(self):
"""
A model (Bio) with a OneToOneField primary key (author) that references
a non-pk field (name) on the related model (Author) is prefetchable.
"""
Bio.objects.bulk_create([
Bio(author=self.author1),
Bio(author=self.author2),
Bio(author=self.author3),
])
authors = Author.objects.filter(
name__in=[self.author1, self.author2, self.author3],
).prefetch_related('bio')
with self.assertNumQueries(2):
for author in authors:
self.assertEqual(author.name, author.bio.author.name)
def test_survives_clone(self):
with self.assertNumQueries(2):
[list(b.first_time_authors.all())