Commit 1252b778 authored by valtron's avatar valtron Committed by Loic Bistuer
Browse files

[1.6.x] Fixed #21760 -- prefetch_related used an inefficient query for reverse FK.

Regression introduced by commit 97774429. Refs #21410.

Conflicts:
	tests/prefetch_related/tests.py

Backport of d3b71b97 from master
parent a3570798
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -599,6 +599,7 @@ answer newbie questions, and generally made Django that much better:
    David Tulig <david.tulig@gmail.com>
    Justine Tunney <jtunney@lobstertech.com>
    Amit Upadhyay <http://www.amitu.com/blog/>
    valtron
    Adam Vandenberg
    Geert Vanderkelen
    Vasil Vangelovski
+3 −1
Original line number Diff line number Diff line
@@ -279,7 +279,9 @@ class ReverseSingleRelatedObjectDescriptor(six.with_metaclass(RenameRelatedObjec
        # 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():
        # The check for len(...) == 1 is a special case that allows the query
        # to be join-less and smaller. Refs #21760.
        if self.field.rel.is_hidden() or len(self.field.foreign_related_fields) == 1:
            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}
+4 −0
Original line number Diff line number Diff line
@@ -67,5 +67,9 @@ Other bugfixes and changes
* Fixed :djadmin:`changepassword` on Windows
  (`#22364 <https://code.djangoproject.com/ticket/22364>`_).

* Fixed regression in ``prefetch_related`` that caused the related objects
  query to include an unnecessary join
  (`#21760 <https://code.djangoproject.com/ticket/21760>`_).

Additionally, Django's vendored version of six, :mod:`django.utils.six` has been
upgraded to the latest release (1.6.1).
+17 −0
Original line number Diff line number Diff line
@@ -2,9 +2,11 @@ from __future__ import absolute_import, unicode_literals

from django.contrib.contenttypes.models import ContentType
from django.db import connection
from django.db.models.query import get_prefetcher
from django.test import TestCase
from django.test.utils import override_settings
from django.utils import six
from django.utils.encoding import force_text

from .models import (Author, Book, Reader, Qualification, Teacher, Department,
    TaggedItem, Bookmark, AuthorAddress, FavoriteAuthors, AuthorWithAge,
@@ -677,3 +679,18 @@ class Ticket21410Tests(TestCase):

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


class Ticket21760Tests(TestCase):

    def setUp(self):
        self.rooms = []
        for _ in range(3):
            house = House.objects.create()
            for _ in range(3):
                self.rooms.append(Room.objects.create(house = house))

    def test_bug(self):
        prefetcher = get_prefetcher(self.rooms[0], 'house')[0]
        queryset = prefetcher.get_prefetch_queryset(list(Room.objects.all()))[0]
        self.assertNotIn(' JOIN ', force_text(queryset.query))