Commit 3c6318e8 authored by Anssi Kääriäinen's avatar Anssi Kääriäinen
Browse files

Fixed #19870 -- Regression in select_related in inheritance cases

There was a regression in case two models inherited the same parent,
and one contained a foreign key to other. When select_related travelled
the foreign key the other model reused the parent join made by the
first model. This was likely caused by Query.join_parent_model()
addition in commit 68985db4.

Thanks to Trac alias loic84 for report & tests.
parent 64911896
Loading
Loading
Loading
Loading
+9 −4
Original line number Diff line number Diff line
@@ -265,14 +265,19 @@ class SQLCompiler(object):
        qn2 = self.connection.ops.quote_name
        aliases = set()
        only_load = self.deferred_to_columns()
        seen = self.query.included_inherited_models.copy()
        if start_alias:
            seen[None] = start_alias
        if not start_alias:
            start_alias = self.query.get_initial_alias()
        # The 'seen_models' is used to optimize checking the needed parent
        # alias for a given field. This also includes None -> start_alias to
        # be used by local fields.
        seen_models = {None: start_alias}

        for field, model in opts.get_fields_with_model():
            if from_parent and model is not None and issubclass(from_parent, model):
                # Avoid loading data for already loaded parents.
                continue
            alias = self.query.join_parent_model(opts, model, start_alias, seen)
            alias = self.query.join_parent_model(opts, model, start_alias,
                                                 seen_models)
            table = self.query.alias_map[alias].table_name
            if table in only_load and field.column not in only_load[table]:
                continue
+14 −0
Original line number Diff line number Diff line
@@ -94,3 +94,17 @@ class Item(models.Model):

    def __str__(self):
        return self.name

# Models for testing bug #19870.
@python_2_unicode_compatible
class Fowl(models.Model):
    name = models.CharField(max_length=10)

    def __str__(self):
        return self.name

class Hen(Fowl):
    pass

class Chick(Fowl):
    mother = models.ForeignKey(Hen)
+12 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ from django.utils import six

from .models import (Building, Child, Device, Port, Item, Country, Connection,
    ClientStatus, State, Client, SpecialClient, TUser, Person, Student,
    Organizer, Class, Enrollment)
    Organizer, Class, Enrollment, Hen, Chick)


class SelectRelatedRegressTests(TestCase):
@@ -162,3 +162,14 @@ class SelectRelatedRegressTests(TestCase):
            # The select_related join was promoted as there is already an
            # existing join.
            self.assertTrue('LEFT OUTER' in str(qs.query))

    def test_regression_19870(self):
        """
        Regression for #19870

        """
        hen = Hen.objects.create(name='Hen')
        chick = Chick.objects.create(name='Chick', mother=hen)

        self.assertEqual(Chick.objects.all()[0].mother.name, 'Hen')
        self.assertEqual(Chick.objects.select_related()[0].mother.name, 'Hen')