Commit 8d65b608 authored by Anssi Kääriäinen's avatar Anssi Kääriäinen
Browse files

Fixed #20955 -- select_related regression

In cases where the same connection (from model A to model B along the
same field) was needed multiple times in a select_related query, the
join setup code mistakenly reused an existing join.
parent c5f768f8
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -664,8 +664,7 @@ class SQLCompiler(object):
                # Use True here because we are looking at the _reverse_ side of
                # the relation, which is always nullable.
                new_nullable = True
                table = model._meta.db_table
                self.fill_related_selections(model._meta, table, cur_depth + 1,
                self.fill_related_selections(model._meta, alias, cur_depth + 1,
                                             next, restricted, new_nullable)

    def deferred_to_columns(self):
+26 −0
Original line number Diff line number Diff line
@@ -501,3 +501,29 @@ class OrderItem(models.Model):

    def __str__(self):
        return '%s' % self.pk

class BaseUser(models.Model):
    pass

@python_2_unicode_compatible
class Task(models.Model):
    title = models.CharField(max_length=10)
    owner = models.ForeignKey(BaseUser, related_name='owner')
    creator = models.ForeignKey(BaseUser, related_name='creator')

    def __str__(self):
        return self.title

@python_2_unicode_compatible
class Staff(models.Model):
    name = models.CharField(max_length=10)

    def __str__(self):
        return self.name

@python_2_unicode_compatible
class StaffUser(BaseUser):
    staff = models.OneToOneField(Staff, related_name='user')

    def __str__(self):
        return self.staff
+21 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ from .models import (
    OneToOneCategory, NullableName, ProxyCategory, SingleObject, RelatedObject,
    ModelA, ModelB, ModelC, ModelD, Responsibility, Job, JobResponsibilities,
    BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book,
    MyObject, Order, OrderItem, SharedConnection)
    MyObject, Order, OrderItem, SharedConnection, Task, Staff, StaffUser)

class BaseQuerysetTest(TestCase):
    def assertValueQuerysetEqual(self, qs, values):
@@ -2992,3 +2992,23 @@ class Ticket14056Tests(TestCase):
            SharedConnection.objects.order_by('-pointera__connection', 'pk'),
            expected_ordering, lambda x: x
        )

class Ticket20955Tests(TestCase):
    def test_ticket_20955(self):
        jack = Staff.objects.create(name='jackstaff')
        jackstaff = StaffUser.objects.create(staff=jack)
        jill = Staff.objects.create(name='jillstaff')
        jillstaff = StaffUser.objects.create(staff=jill)
        task = Task.objects.create(creator=jackstaff, owner=jillstaff, title="task")
        task_get = Task.objects.get(pk=task.pk)
        # Load data so that assertNumQueries doesn't complain about the get
        # version's queries.
        task_get.creator.staffuser.staff
        task_get.owner.staffuser.staff
        task_select_related = Task.objects.select_related(
            'creator__staffuser__staff', 'owner__staffuser__staff').get(pk=task.pk)
        with self.assertNumQueries(0):
            self.assertEqual(task_select_related.creator.staffuser.staff,
                             task_get.creator.staffuser.staff)
            self.assertEqual(task_select_related.owner.staffuser.staff,
                             task_get.owner.staffuser.staff)