From f399a804c9436a5d3ef9e2b73c337904af2c753d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anssi=20K=C3=A4=C3=A4ri=C3=A4inen?= Date: Sat, 15 Sep 2012 21:11:14 +0300 Subject: [PATCH] Fixed #17485 regression -- only + select_related interaction When doing deeper than one level select_related() + only queries(), the code introduced in b6c356b7bb97f3d6d4831b31e67868313bbbc090 errored incorrectly. Thanks to mrmachine for report & test case. --- django/db/models/sql/compiler.py | 6 +++++- tests/regressiontests/defer_regress/models.py | 3 +++ tests/regressiontests/defer_regress/tests.py | 16 +++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 28d2404858..f06d6b11a4 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -609,8 +609,12 @@ class SQLCompiler(object): restricted = False for f, model in opts.get_fields_with_model(): + # The get_fields_with_model() returns None for fields that live + # in the field's local model. So, for those fields we want to use + # the f.model - that is the field's local model. + field_model = model or f.model if not select_related_descend(f, restricted, requested, - only_load.get(model or self.query.model)): + only_load.get(field_model)): continue # The "avoid" set is aliases we want to avoid just for this # particular branch of the recursion. They aren't permanently diff --git a/tests/regressiontests/defer_regress/models.py b/tests/regressiontests/defer_regress/models.py index d02adccde9..444649ac92 100644 --- a/tests/regressiontests/defer_regress/models.py +++ b/tests/regressiontests/defer_regress/models.py @@ -52,6 +52,9 @@ class SimpleItem(models.Model): class Feature(models.Model): item = models.ForeignKey(SimpleItem) +class SpecialFeature(models.Model): + feature = models.ForeignKey(Feature) + class ItemAndSimpleItem(models.Model): item = models.ForeignKey(Item) simple = models.ForeignKey(SimpleItem) diff --git a/tests/regressiontests/defer_regress/tests.py b/tests/regressiontests/defer_regress/tests.py index 53bb59f5b3..c77ca32135 100644 --- a/tests/regressiontests/defer_regress/tests.py +++ b/tests/regressiontests/defer_regress/tests.py @@ -9,7 +9,7 @@ from django.db.models.loading import cache from django.test import TestCase from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy, - SimpleItem, Feature, ItemAndSimpleItem) + SimpleItem, Feature, ItemAndSimpleItem, SpecialFeature) class DeferRegressionTest(TestCase): @@ -115,6 +115,7 @@ class DeferRegressionTest(TestCase): RelatedItem, ResolveThis, SimpleItem, + SpecialFeature, ] ) @@ -152,6 +153,7 @@ class DeferRegressionTest(TestCase): "RelatedItem_Deferred_item_id", "ResolveThis", "SimpleItem", + "SpecialFeature", ] ) @@ -197,6 +199,18 @@ class DeferRegressionTest(TestCase): self.assertEqual(obj.item, item2) self.assertEqual(obj.item_id, item2.id) + def test_only_with_select_related(self): + # Test for #17485. + item = SimpleItem.objects.create(name='first', value=47) + feature = Feature.objects.create(item=item) + SpecialFeature.objects.create(feature=feature) + + qs = Feature.objects.only('item__name').select_related('item') + self.assertEqual(len(qs), 1) + + qs = SpecialFeature.objects.only('feature__item__name').select_related('feature__item') + self.assertEqual(len(qs), 1) + def test_deferred_class_factory(self): from django.db.models.query_utils import deferred_class_factory new_class = deferred_class_factory(Item,