Skip to content

Commit

Permalink
Fixed #20955 -- select_related regression
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
akaariai committed Aug 22, 2013
1 parent c5f768f commit 8d65b60
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
5 changes: 2 additions & 3 deletions django/db/models/sql/compiler.py
Expand Up @@ -664,9 +664,8 @@ def fill_related_selections(self, opts=None, root_alias=None, cur_depth=1,
# Use True here because we are looking at the _reverse_ side of
# the relation, which is always nullable.
new_nullable = True
table = model._meta.db_table
self.fill_related_selections(model._meta, table, cur_depth + 1,
next, restricted, new_nullable)
self.fill_related_selections(model._meta, alias, cur_depth + 1,
next, restricted, new_nullable)

def deferred_to_columns(self):
"""
Expand Down
26 changes: 26 additions & 0 deletions tests/queries/models.py
Expand Up @@ -501,3 +501,29 @@ class Meta:

def __str__(self):
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
22 changes: 21 additions & 1 deletion tests/queries/tests.py
Expand Up @@ -25,7 +25,7 @@
OneToOneCategory, NullableName, ProxyCategory, SingleObject, RelatedObject,
ModelA, ModelB, ModelC, ModelD, Responsibility, Job, JobResponsibilities,
BaseA, FK1, Identifier, Program, Channel, Page, Paragraph, Chapter, Book,
MyObject, Order, OrderItem, SharedConnection)
MyObject, Order, OrderItem, SharedConnection, Task, Staff, StaffUser)

class BaseQuerysetTest(TestCase):
def assertValueQuerysetEqual(self, qs, values):
Expand Down Expand Up @@ -2992,3 +2992,23 @@ def test_ticket_14056(self):
SharedConnection.objects.order_by('-pointera__connection', 'pk'),
expected_ordering, 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)

0 comments on commit 8d65b60

Please sign in to comment.