mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.6.x] Fixed #20955 -- select_related regression
In cases where the same connection (from model A to model B along the
same field) was needed multiple times in a select_related query, the
join setup code mistakenly reused an existing join.
Backpatch of 8d65b6082c.
Conflicts:
	django/db/models/sql/compiler.py
	tests/queries/tests.py
			
			
This commit is contained in:
		| @@ -687,8 +687,7 @@ class SQLCompiler(object): | |||||||
|                 # Use True here because we are looking at the _reverse_ side of |                 # Use True here because we are looking at the _reverse_ side of | ||||||
|                 # the relation, which is always nullable. |                 # the relation, which is always nullable. | ||||||
|                 new_nullable = True |                 new_nullable = True | ||||||
|                 table = model._meta.db_table |                 self.fill_related_selections(model._meta, alias, cur_depth + 1, | ||||||
|                 self.fill_related_selections(model._meta, table, cur_depth+1, |  | ||||||
|                                              next, restricted, new_nullable) |                                              next, restricted, new_nullable) | ||||||
|  |  | ||||||
|     def deferred_to_columns(self): |     def deferred_to_columns(self): | ||||||
|   | |||||||
| @@ -497,3 +497,29 @@ class OrderItem(models.Model): | |||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return '%s' % self.pk |         return '%s' % self.pk | ||||||
|  |  | ||||||
|  | class BaseUser(models.Model): | ||||||
|  |     pass | ||||||
|  |  | ||||||
|  | @python_2_unicode_compatible | ||||||
|  | class Task(models.Model): | ||||||
|  |     title = models.CharField(max_length=10) | ||||||
|  |     owner = models.ForeignKey(BaseUser, related_name='owner') | ||||||
|  |     creator = models.ForeignKey(BaseUser, related_name='creator') | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.title | ||||||
|  |  | ||||||
|  | @python_2_unicode_compatible | ||||||
|  | class Staff(models.Model): | ||||||
|  |     name = models.CharField(max_length=10) | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.name | ||||||
|  |  | ||||||
|  | @python_2_unicode_compatible | ||||||
|  | class StaffUser(BaseUser): | ||||||
|  |     staff = models.OneToOneField(Staff, related_name='user') | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.staff | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ from .models import ( | |||||||
|     OneToOneCategory, NullableName, ProxyCategory, SingleObject, RelatedObject, |     OneToOneCategory, NullableName, ProxyCategory, SingleObject, RelatedObject, | ||||||
|     ModelA, ModelB, ModelC, ModelD, Responsibility, Job, JobResponsibilities, |     ModelA, ModelB, ModelC, ModelD, Responsibility, Job, JobResponsibilities, | ||||||
|     BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book, |     BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book, | ||||||
|     MyObject, Order, OrderItem) |     MyObject, Order, OrderItem, Task, Staff, StaffUser) | ||||||
|  |  | ||||||
|  |  | ||||||
| class BaseQuerysetTest(TestCase): | class BaseQuerysetTest(TestCase): | ||||||
| @@ -2943,3 +2943,23 @@ class RelatedLookupTypeTests(TestCase): | |||||||
|         self.assertQuerysetEqual( |         self.assertQuerysetEqual( | ||||||
|             ObjectB.objects.filter(objecta__in=[wrong_type]), |             ObjectB.objects.filter(objecta__in=[wrong_type]), | ||||||
|             [ob], lambda x: x) |             [ob], lambda x: x) | ||||||
|  |  | ||||||
|  | class Ticket20955Tests(TestCase): | ||||||
|  |     def test_ticket_20955(self): | ||||||
|  |         jack = Staff.objects.create(name='jackstaff') | ||||||
|  |         jackstaff = StaffUser.objects.create(staff=jack) | ||||||
|  |         jill = Staff.objects.create(name='jillstaff') | ||||||
|  |         jillstaff = StaffUser.objects.create(staff=jill) | ||||||
|  |         task = Task.objects.create(creator=jackstaff, owner=jillstaff, title="task") | ||||||
|  |         task_get = Task.objects.get(pk=task.pk) | ||||||
|  |         # Load data so that assertNumQueries doesn't complain about the get | ||||||
|  |         # version's queries. | ||||||
|  |         task_get.creator.staffuser.staff | ||||||
|  |         task_get.owner.staffuser.staff | ||||||
|  |         task_select_related = Task.objects.select_related( | ||||||
|  |             'creator__staffuser__staff', 'owner__staffuser__staff').get(pk=task.pk) | ||||||
|  |         with self.assertNumQueries(0): | ||||||
|  |             self.assertEqual(task_select_related.creator.staffuser.staff, | ||||||
|  |                              task_get.creator.staffuser.staff) | ||||||
|  |             self.assertEqual(task_select_related.owner.staffuser.staff, | ||||||
|  |                              task_get.owner.staffuser.staff) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user