Commit f399a804 authored by Anssi Kääriäinen's avatar Anssi Kääriäinen
Browse files

Fixed #17485 regression -- only + select_related interaction

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

Thanks to mrmachine for report & test case.
parent 935a8635
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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)
+15 −1
Original line number Diff line number Diff line
@@ -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,