From 7da37699e8d7124f5d0cfaba931772333c24ef83 Mon Sep 17 00:00:00 2001 From: Daniel Hillier Date: Wed, 14 Dec 2016 01:06:54 +1100 Subject: [PATCH] Fixed #27594 -- Fixed select_related() with reverse self-referential OneToOneField. Fixed definition of `klass_info['from_parent']` so that two models aren't considered from a parent class if the model classes are the same. --- django/db/models/sql/compiler.py | 2 +- tests/select_related_onetoone/models.py | 9 +++++++++ tests/select_related_onetoone/tests.py | 12 ++++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index c7455ecceb..3e61f8a925 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -713,7 +713,7 @@ class SQLCompiler(object): _, _, _, joins, _ = self.query.setup_joins([related_field_name], opts, root_alias) alias = joins[-1] - from_parent = issubclass(model, opts.model) + from_parent = issubclass(model, opts.model) and model is not opts.model klass_info = { 'model': model, 'field': f, diff --git a/tests/select_related_onetoone/models.py b/tests/select_related_onetoone/models.py index cb9221ea1c..76c45659af 100644 --- a/tests/select_related_onetoone/models.py +++ b/tests/select_related_onetoone/models.py @@ -102,3 +102,12 @@ class Child3(Child2): class Child4(Child1): value4 = models.IntegerField() + + +class LinkedList(models.Model): + name = models.CharField(max_length=50) + previous_item = models.OneToOneField( + 'self', models.CASCADE, + related_name='next_item', + blank=True, null=True, + ) diff --git a/tests/select_related_onetoone/tests.py b/tests/select_related_onetoone/tests.py index 3f45bba19c..a7d646e25d 100644 --- a/tests/select_related_onetoone/tests.py +++ b/tests/select_related_onetoone/tests.py @@ -4,8 +4,9 @@ from django.core.exceptions import FieldError from django.test import SimpleTestCase, TestCase from .models import ( - AdvancedUserStat, Child1, Child2, Child3, Child4, Image, Parent1, Parent2, - Product, StatDetails, User, UserProfile, UserStat, UserStatResult, + AdvancedUserStat, Child1, Child2, Child3, Child4, Image, LinkedList, + Parent1, Parent2, Product, StatDetails, User, UserProfile, UserStat, + UserStatResult, ) @@ -207,6 +208,13 @@ class ReverseSelectRelatedTestCase(TestCase): self.assertEqual(p.child1.name1, 'n1') self.assertEqual(p.child1.child4.name1, 'n1') + def test_self_relation(self): + item1 = LinkedList.objects.create(name='item1') + LinkedList.objects.create(name='item2', previous_item=item1) + with self.assertNumQueries(1): + item1_db = LinkedList.objects.select_related('next_item').get(name='item1') + self.assertEqual(item1_db.next_item.name, 'item2') + class ReverseSelectRelatedValidationTests(SimpleTestCase): """