Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.0.X] 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.

Backport of r10136 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10138 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 2fba099779324dd460184849ba221d233c1a6751 1 parent 2b098e6
Malcolm Tredinnick authored March 24, 2009
14  django/db/models/sql/query.py
@@ -510,6 +510,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
510 510
                 alias = self.included_inherited_models[model]
511 511
             if as_pairs:
512 512
                 result.append((alias, field.column))
  513
+                aliases.add(alias)
513 514
                 continue
514 515
             if with_aliases and field.column in col_aliases:
515 516
                 c_alias = 'Col%d' % len(col_aliases)
@@ -524,7 +525,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
524 525
                 if with_aliases:
525 526
                     col_aliases.add(field.column)
526 527
         if as_pairs:
527  
-            return result, None
  528
+            return result, aliases
528 529
         return result, aliases
529 530
 
530 531
     def get_from_clause(self):
@@ -1076,6 +1077,7 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
1076 1077
             if model:
1077 1078
                 int_opts = opts
1078 1079
                 alias = root_alias
  1080
+                alias_chain = []
1079 1081
                 for int_model in opts.get_base_chain(model):
1080 1082
                     lhs_col = int_opts.parents[int_model].column
1081 1083
                     dedupe = lhs_col in opts.duplicate_targets
@@ -1087,8 +1089,11 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
1087 1089
                     alias = self.join((alias, int_opts.db_table, lhs_col,
1088 1090
                             int_opts.pk.column), exclusions=used,
1089 1091
                             promote=promote)
  1092
+                    alias_chain.append(alias)
1090 1093
                     for (dupe_opts, dupe_col) in dupe_set:
1091 1094
                         self.update_dupe_avoidance(dupe_opts, dupe_col, alias)
  1095
+                if self.alias_map[root_alias][JOIN_TYPE] == self.LOUTER:
  1096
+                    self.promote_alias_chain(alias_chain, True)
1092 1097
             else:
1093 1098
                 alias = root_alias
1094 1099
 
@@ -1102,8 +1107,11 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
1102 1107
                     f.rel.get_related_field().column),
1103 1108
                     exclusions=used.union(avoid), promote=promote)
1104 1109
             used.add(alias)
1105  
-            self.related_select_cols.extend(self.get_default_columns(
1106  
-                start_alias=alias, opts=f.rel.to._meta, as_pairs=True)[0])
  1110
+            columns, aliases = self.get_default_columns(start_alias=alias,
  1111
+                    opts=f.rel.to._meta, as_pairs=True)
  1112
+            self.related_select_cols.extend(columns)
  1113
+            if self.alias_map[alias][JOIN_TYPE] == self.LOUTER:
  1114
+                self.promote_alias_chain(aliases, True)
1107 1115
             self.related_select_fields.extend(f.rel.to._meta.fields)
1108 1116
             if restricted:
1109 1117
                 next = requested.get(f.name, {})
18  tests/regressiontests/queries/models.py
@@ -16,10 +16,17 @@
16 16
 except NameError:
17 17
     from django.utils.itercompat import sorted
18 18
 
  19
+class DumbCategory(models.Model):
  20
+    pass
  21
+
  22
+class NamedCategory(DumbCategory):
  23
+    name = models.CharField(max_length=10)
  24
+
19 25
 class Tag(models.Model):
20 26
     name = models.CharField(max_length=10)
21 27
     parent = models.ForeignKey('self', blank=True, null=True,
22 28
             related_name='children')
  29
+    category = models.ForeignKey(NamedCategory, null=True, default=None)
23 30
 
24 31
     class Meta:
25 32
         ordering = ['name']
@@ -266,8 +273,9 @@ def __unicode__(self):
266 273
 
267 274
 
268 275
 __test__ = {'API_TESTS':"""
269  
->>> t1 = Tag.objects.create(name='t1')
270  
->>> t2 = Tag.objects.create(name='t2', parent=t1)
  276
+>>> generic = NamedCategory.objects.create(name="Generic")
  277
+>>> t1 = Tag.objects.create(name='t1', category=generic)
  278
+>>> t2 = Tag.objects.create(name='t2', parent=t1, category=generic)
271 279
 >>> t3 = Tag.objects.create(name='t3', parent=t1)
272 280
 >>> t4 = Tag.objects.create(name='t4', parent=t3)
273 281
 >>> t5 = Tag.objects.create(name='t5', parent=t3)
@@ -726,6 +734,12 @@ def __unicode__(self):
726 734
 >>> Tag.objects.select_related('parent').order_by('name')
727 735
 [<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
728 736
 
  737
+Bug #9926
  738
+>>> Tag.objects.select_related("parent", "category").order_by('name')
  739
+[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
  740
+>>> Tag.objects.select_related('parent', "parent__category").order_by('name')
  741
+[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
  742
+
729 743
 Bug #6180, #6203 -- dates with limits and/or counts
730 744
 >>> Item.objects.count()
731 745
 4
25  tests/regressiontests/select_related_regress/models.py
@@ -65,6 +65,23 @@ class Client(models.Model):
@@ -140,4 +157,12 @@ class Client(models.Model):

0 notes on commit 2fba099

Please sign in to comment.
Something went wrong with that request. Please try again.