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 68985db482.

Thanks to Trac alias loic84 for report & tests.
This commit is contained in:
Anssi Kääriäinen 2013-02-21 11:12:08 +02:00
parent 649118961c
commit 3c6318e831
3 changed files with 35 additions and 5 deletions

View File

@ -265,14 +265,19 @@ class SQLCompiler(object):
qn2 = self.connection.ops.quote_name qn2 = self.connection.ops.quote_name
aliases = set() aliases = set()
only_load = self.deferred_to_columns() only_load = self.deferred_to_columns()
seen = self.query.included_inherited_models.copy() if not start_alias:
if start_alias: start_alias = self.query.get_initial_alias()
seen[None] = start_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(): for field, model in opts.get_fields_with_model():
if from_parent and model is not None and issubclass(from_parent, model): if from_parent and model is not None and issubclass(from_parent, model):
# Avoid loading data for already loaded parents. # Avoid loading data for already loaded parents.
continue 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 table = self.query.alias_map[alias].table_name
if table in only_load and field.column not in only_load[table]: if table in only_load and field.column not in only_load[table]:
continue continue

View File

@ -94,3 +94,17 @@ class Item(models.Model):
def __str__(self): def __str__(self):
return self.name 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)

View File

@ -5,7 +5,7 @@ from django.utils import six
from .models import (Building, Child, Device, Port, Item, Country, Connection, from .models import (Building, Child, Device, Port, Item, Country, Connection,
ClientStatus, State, Client, SpecialClient, TUser, Person, Student, ClientStatus, State, Client, SpecialClient, TUser, Person, Student,
Organizer, Class, Enrollment) Organizer, Class, Enrollment, Hen, Chick)
class SelectRelatedRegressTests(TestCase): class SelectRelatedRegressTests(TestCase):
@ -162,3 +162,14 @@ class SelectRelatedRegressTests(TestCase):
# The select_related join was promoted as there is already an # The select_related join was promoted as there is already an
# existing join. # existing join.
self.assertTrue('LEFT OUTER' in str(qs.query)) 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')