Fixed #17485 regression -- only + select_related interaction

When doing deeper than one level select_related() + only queries(), the
code introduced in b6c356b7bb errored
incorrectly.

Thanks to mrmachine for report & test case.
This commit is contained in:
Anssi Kääriäinen 2012-09-15 21:11:14 +03:00
parent 935a8635c2
commit f399a804c9
3 changed files with 23 additions and 2 deletions

View File

@ -609,8 +609,12 @@ class SQLCompiler(object):
restricted = False restricted = False
for f, model in opts.get_fields_with_model(): 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, if not select_related_descend(f, restricted, requested,
only_load.get(model or self.query.model)): only_load.get(field_model)):
continue continue
# The "avoid" set is aliases we want to avoid just for this # The "avoid" set is aliases we want to avoid just for this
# particular branch of the recursion. They aren't permanently # particular branch of the recursion. They aren't permanently

View File

@ -52,6 +52,9 @@ class SimpleItem(models.Model):
class Feature(models.Model): class Feature(models.Model):
item = models.ForeignKey(SimpleItem) item = models.ForeignKey(SimpleItem)
class SpecialFeature(models.Model):
feature = models.ForeignKey(Feature)
class ItemAndSimpleItem(models.Model): class ItemAndSimpleItem(models.Model):
item = models.ForeignKey(Item) item = models.ForeignKey(Item)
simple = models.ForeignKey(SimpleItem) simple = models.ForeignKey(SimpleItem)

View File

@ -9,7 +9,7 @@ from django.db.models.loading import cache
from django.test import TestCase from django.test import TestCase
from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy, from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy,
SimpleItem, Feature, ItemAndSimpleItem) SimpleItem, Feature, ItemAndSimpleItem, SpecialFeature)
class DeferRegressionTest(TestCase): class DeferRegressionTest(TestCase):
@ -115,6 +115,7 @@ class DeferRegressionTest(TestCase):
RelatedItem, RelatedItem,
ResolveThis, ResolveThis,
SimpleItem, SimpleItem,
SpecialFeature,
] ]
) )
@ -152,6 +153,7 @@ class DeferRegressionTest(TestCase):
"RelatedItem_Deferred_item_id", "RelatedItem_Deferred_item_id",
"ResolveThis", "ResolveThis",
"SimpleItem", "SimpleItem",
"SpecialFeature",
] ]
) )
@ -197,6 +199,18 @@ class DeferRegressionTest(TestCase):
self.assertEqual(obj.item, item2) self.assertEqual(obj.item, item2)
self.assertEqual(obj.item_id, item2.id) 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): def test_deferred_class_factory(self):
from django.db.models.query_utils import deferred_class_factory from django.db.models.query_utils import deferred_class_factory
new_class = deferred_class_factory(Item, new_class = deferred_class_factory(Item,