mirror of
				https://github.com/django/django.git
				synced 2025-10-31 07:57:51 +03:00 
			
		
		
		
	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
This commit is contained in:
		
							parent
							
								
									c5aa6fa710
								
							
						
					
					
						commit
						fd46f673bd
					
				|  | @ -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,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 | ||||
|  |  | |||
|  | @ -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>] | ||||
| 
 | ||||
| """} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user