Commit b107421a authored by Loic Bistuer's avatar Loic Bistuer Committed by Anssi Kääriäinen
Browse files

[1.6.x] Fixed #21410 -- prefetch_related() for ForeignKeys with related_name='+'

Regression introduced by commit 97774429.

Thanks to trac username troygrosfield for the report and test case.

Backpatch of cb834488 from master.

Conflicts:

	tests/prefetch_related/models.py
parent b6acc4f7
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -273,7 +273,17 @@ class ReverseSingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjec
        rel_obj_attr = self.field.get_foreign_related_value
        instance_attr = self.field.get_local_related_value
        instances_dict = dict((instance_attr(inst), inst) for inst in instances)
        related_field = self.field.foreign_related_fields[0]

        # FIXME: This will need to be revisited when we introduce support for
        # composite fields. In the meantime we take this practical approach to
        # solve a regression on 1.6 when the reverse manager in hidden
        # (related_name ends with a '+'). Refs #21410.
        if self.field.rel.is_hidden():
            query = {'%s__in' % related_field.name: set(instance_attr(inst)[0] for inst in instances)}
        else:
            query = {'%s__in' % self.field.related_query_name(): instances}

        qs = self.get_queryset(instance=instances[0]).filter(**query)
        # Since we're going to assign directly in the cache,
        # we must manage the reverse relation cache manually.
+15 −0
Original line number Diff line number Diff line
@@ -215,3 +215,18 @@ class WordEntry(models.Model):

    def __str__(self):
        return "%s (%s)" % (self.name, self.id)


## Ticket #21410: Regression when related_name="+"

@python_2_unicode_compatible
class Author2(models.Model):
    name = models.CharField(max_length=50, unique=True)
    first_book = models.ForeignKey('Book', related_name='first_time_authors+')
    favorite_books = models.ManyToManyField('Book', related_name='+')

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['id']
+27 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ from django.utils import six
from .models import (Author, Book, Reader, Qualification, Teacher, Department,
    TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge,
    BookWithYear, BookReview, Person, House, Room, Employee, Comment,
    LessonEntry, WordEntry)
    LessonEntry, WordEntry, Author2)


class PrefetchRelatedTests(TestCase):
@@ -651,3 +651,29 @@ class Ticket19607Tests(TestCase):

    def test_bug(self):
        list(WordEntry.objects.prefetch_related('lesson_entry', 'lesson_entry__wordentry_set'))


class Ticket21410Tests(TestCase):

    def setUp(self):
        self.book1 = Book.objects.create(title="Poems")
        self.book2 = Book.objects.create(title="Jane Eyre")
        self.book3 = Book.objects.create(title="Wuthering Heights")
        self.book4 = Book.objects.create(title="Sense and Sensibility")

        self.author1 = Author2.objects.create(name="Charlotte",
                                             first_book=self.book1)
        self.author2 = Author2.objects.create(name="Anne",
                                             first_book=self.book1)
        self.author3 = Author2.objects.create(name="Emily",
                                             first_book=self.book1)
        self.author4 = Author2.objects.create(name="Jane",
                                             first_book=self.book4)

        self.author1.favorite_books.add(self.book1, self.book2, self.book3)
        self.author2.favorite_books.add(self.book1)
        self.author3.favorite_books.add(self.book2)
        self.author4.favorite_books.add(self.book3)

    def test_bug(self):
        list(Author2.objects.prefetch_related('first_book', 'favorite_books'))