Commit fd46f673 authored by Malcolm Tredinnick's avatar Malcolm Tredinnick
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
parent c5aa6fa7
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -770,6 +770,7 @@ class BaseQuery(object):
                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 @@ class BaseQuery(object):
                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 @@ class BaseQuery(object):
            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 @@ class BaseQuery(object):
                    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 @@ class BaseQuery(object):
                    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, {})
+16 −2
Original line number Diff line number Diff line
@@ -16,10 +16,17 @@ try:
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 @@ class Plaything(models.Model):


__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 @@ Bug #6981
>>> 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 −0
Original line number Diff line number Diff line
@@ -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 @@ for country before getting status.
<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>]

"""}