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

Avoided creation of deferred model from another deferred model

Also never create deferred model when no attrs are deferred.
parent 5b0375ec
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -186,6 +186,14 @@ def deferred_class_factory(model, attrs):
    being replaced with DeferredAttribute objects. The "pk_value" ties the
    deferred attributes to a particular instance of the model.
    """
    if not attrs:
        return model
    # Never create deferred models based on deferred model
    if model._deferred:
        # Deferred models are proxies for the non-deferred model. We never
        # create chains of defers => proxy_for_model is the non-deferred
        # model.
        model = model._meta.proxy_for_model
    # The app registry wants a unique name for each model, otherwise the new
    # class won't be created (we get an exception). Therefore, we generate
    # the name using the passed in attrs. It's OK to reuse an existing class
+12 −1
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ from django.apps import apps
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.backends.db import SessionStore
from django.db.models import Count
from django.db.models.query_utils import deferred_class_factory, DeferredAttribute
from django.test import TestCase, override_settings

from .models import (
@@ -233,7 +234,6 @@ class DeferRegressionTest(TestCase):
        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,
            ('this_is_some_very_long_attribute_name_so_modelname_truncation_is_triggered',))
@@ -241,6 +241,17 @@ class DeferRegressionTest(TestCase):
            new_class.__name__,
            'Item_Deferred_this_is_some_very_long_attribute_nac34b1f495507dad6b02e2cb235c875e')

    def test_deferred_class_factory_already_deferred(self):
        deferred_item1 = deferred_class_factory(Item, ('name',))
        deferred_item2 = deferred_class_factory(deferred_item1, ('value',))
        self.assertIs(deferred_item2._meta.proxy_for_model, Item)
        self.assertFalse(isinstance(deferred_item2.__dict__.get('name'), DeferredAttribute))
        self.assertTrue(isinstance(deferred_item2.__dict__.get('value'), DeferredAttribute))

    def test_deferred_class_factory_no_attrs(self):
        deferred_cls = deferred_class_factory(Item, ())
        self.assertFalse(deferred_cls._deferred)


class DeferAnnotateSelectRelatedTest(TestCase):
    def test_defer_annotate_select_related(self):