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:
parent
649118961c
commit
3c6318e831
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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')
|
||||||
|
|
Loading…
Reference in New Issue