Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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 authored March 24, 2009
14  django/db/models/sql/query.py
@@ -770,6 +770,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
770 770
                 continue
771 771
             if as_pairs:
772 772
                 result.append((alias, field.column))
  773
+                aliases.add(alias)
773 774
                 continue
774 775
             if with_aliases and field.column in col_aliases:
775 776
                 c_alias = 'Col%d' % len(col_aliases)
@@ -784,7 +785,7 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
784 785
                 if with_aliases:
785 786
                     col_aliases.add(field.column)
786 787
         if as_pairs:
787  
-            return result, None
  788
+            return result, aliases
788 789
         return result, aliases
789 790
 
790 791
     def get_from_clause(self):
@@ -1342,6 +1343,7 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
1342 1343
             if model:
1343 1344
                 int_opts = opts
1344 1345
                 alias = root_alias
  1346
+                alias_chain = []
1345 1347
                 for int_model in opts.get_base_chain(model):
1346 1348
                     lhs_col = int_opts.parents[int_model].column
1347 1349
                     dedupe = lhs_col in opts.duplicate_targets
@@ -1353,8 +1355,11 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
1353 1355
                     alias = self.join((alias, int_opts.db_table, lhs_col,
1354 1356
                             int_opts.pk.column), exclusions=used,
1355 1357
                             promote=promote)
  1358
+                    alias_chain.append(alias)
1356 1359
                     for (dupe_opts, dupe_col) in dupe_set:
1357 1360
                         self.update_dupe_avoidance(dupe_opts, dupe_col, alias)
  1361
+                if self.alias_map[root_alias][JOIN_TYPE] == self.LOUTER:
  1362
+                    self.promote_alias_chain(alias_chain, True)
1358 1363
             else:
1359 1364
                 alias = root_alias
1360 1365
 
@@ -1368,8 +1373,11 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
1368 1373
                     f.rel.get_related_field().column),
1369 1374
                     exclusions=used.union(avoid), promote=promote)
1370 1375
             used.add(alias)
1371  
-            self.related_select_cols.extend(self.get_default_columns(
1372  
-                start_alias=alias, opts=f.rel.to._meta, as_pairs=True)[0])
  1376
+            columns, aliases = self.get_default_columns(start_alias=alias,
  1377
+                    opts=f.rel.to._meta, as_pairs=True)
  1378
+            self.related_select_cols.extend(columns)
  1379
+            if self.alias_map[alias][JOIN_TYPE] == self.LOUTER:
  1380
+                self.promote_alias_chain(aliases, True)
1373 1381
             self.related_select_fields.extend(f.rel.to._meta.fields)
1374 1382
             if restricted:
1375 1383
                 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 fd46f67

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