Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #9926 -- Fixes for some select_related() situations.

Using select_related(...) across a nullable relation to a multi-table
model inheritance situation no longer excludes results. Thanks to AdamG
for a test demonstrating part of the problem.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10136 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit fd46f673bd83d8ed26ed54075439236e65f2d015 1 parent c5aa6fa
Malcolm Tredinnick malcolmt authored
14 django/db/models/sql/query.py
View
@@ -770,6 +770,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
continue
if as_pairs:
result.append((alias, field.column))
+ aliases.add(alias)
continue
if with_aliases and field.column in col_aliases:
c_alias = 'Col%d' % len(col_aliases)
@@ -784,7 +785,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
if with_aliases:
col_aliases.add(field.column)
if as_pairs:
- return result, None
+ return result, aliases
return result, aliases
def get_from_clause(self):
@@ -1342,6 +1343,7 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
if model:
int_opts = opts
alias = root_alias
+ alias_chain = []
for int_model in opts.get_base_chain(model):
lhs_col = int_opts.parents[int_model].column
dedupe = lhs_col in opts.duplicate_targets
@@ -1353,8 +1355,11 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
alias = self.join((alias, int_opts.db_table, lhs_col,
int_opts.pk.column), exclusions=used,
promote=promote)
+ alias_chain.append(alias)
for (dupe_opts, dupe_col) in dupe_set:
self.update_dupe_avoidance(dupe_opts, dupe_col, alias)
+ if self.alias_map[root_alias][JOIN_TYPE] == self.LOUTER:
+ self.promote_alias_chain(alias_chain, True)
else:
alias = root_alias
@@ -1368,8 +1373,11 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
f.rel.get_related_field().column),
exclusions=used.union(avoid), promote=promote)
used.add(alias)
- self.related_select_cols.extend(self.get_default_columns(
- start_alias=alias, opts=f.rel.to._meta, as_pairs=True)[0])
+ columns, aliases = self.get_default_columns(start_alias=alias,
+ opts=f.rel.to._meta, as_pairs=True)
+ self.related_select_cols.extend(columns)
+ if self.alias_map[alias][JOIN_TYPE] == self.LOUTER:
+ self.promote_alias_chain(aliases, True)
self.related_select_fields.extend(f.rel.to._meta.fields)
if restricted:
next = requested.get(f.name, {})
18 tests/regressiontests/queries/models.py
View
@@ -16,10 +16,17 @@
except NameError:
from django.utils.itercompat import sorted
+class DumbCategory(models.Model):
+ pass
+
+class NamedCategory(DumbCategory):
+ name = models.CharField(max_length=10)
+
class Tag(models.Model):
name = models.CharField(max_length=10)
parent = models.ForeignKey('self', blank=True, null=True,
related_name='children')
+ category = models.ForeignKey(NamedCategory, null=True, default=None)
class Meta:
ordering = ['name']
@@ -266,8 +273,9 @@ def __unicode__(self):
__test__ = {'API_TESTS':"""
->>> t1 = Tag.objects.create(name='t1')
->>> t2 = Tag.objects.create(name='t2', parent=t1)
+>>> generic = NamedCategory.objects.create(name="Generic")
+>>> t1 = Tag.objects.create(name='t1', category=generic)
+>>> t2 = Tag.objects.create(name='t2', parent=t1, category=generic)
>>> t3 = Tag.objects.create(name='t3', parent=t1)
>>> t4 = Tag.objects.create(name='t4', parent=t3)
>>> t5 = Tag.objects.create(name='t5', parent=t3)
@@ -726,6 +734,12 @@ def __unicode__(self):
>>> Tag.objects.select_related('parent').order_by('name')
[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
+Bug #9926
+>>> Tag.objects.select_related("parent", "category").order_by('name')
+[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
+>>> Tag.objects.select_related('parent', "parent__category").order_by('name')
+[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
+
Bug #6180, #6203 -- dates with limits and/or counts
>>> Item.objects.count()
4
25 tests/regressiontests/select_related_regress/models.py
View
@@ -65,6 +65,23 @@ class Client(models.Model):
state = models.ForeignKey(State, null=True)
status = models.ForeignKey(ClientStatus)
+# Some model inheritance exercises
+class Parent(models.Model):
+ name = models.CharField(max_length=10)
+
+ def __unicode__(self):
+ return self.name
+
+class Child(Parent):
+ value = models.IntegerField()
+
+class Item(models.Model):
+ name = models.CharField(max_length=10)
+ child = models.ForeignKey(Child, null=True)
+
+ def __unicode__(self):
+ return self.name
+
__test__ = {'API_TESTS': """
Regression test for bug #7110. When using select_related(), we must query the
Device and Building tables using two different aliases (each) in order to
@@ -140,4 +157,12 @@ class Client(models.Model):
<ClientStatus: ClientStatus object>
>>> Client.objects.select_related('status')[0].status
<ClientStatus: ClientStatus object>
+
+Exercising select_related() with multi-table model inheritance.
+>>> c1 = Child.objects.create(name="child1", value=42)
+>>> _ = Item.objects.create(name="item1", child=c1)
+>>> _ = Item.objects.create(name="item2")
+>>> Item.objects.select_related("child").order_by("name")
+[<Item: item1>, <Item: item2>]
+
"""}
Please sign in to comment.
Something went wrong with that request. Please try again.