Kaydet (Commit) f7dba618 authored tarafından Anssi Kääriäinen's avatar Anssi Kääriäinen

Avoided creation of deferred model from another deferred model

Also never create deferred model when no attrs are deferred.
üst 5b0375ec
...@@ -186,6 +186,14 @@ def deferred_class_factory(model, attrs): ...@@ -186,6 +186,14 @@ def deferred_class_factory(model, attrs):
being replaced with DeferredAttribute objects. The "pk_value" ties the being replaced with DeferredAttribute objects. The "pk_value" ties the
deferred attributes to a particular instance of the model. 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 # 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 # 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 # the name using the passed in attrs. It's OK to reuse an existing class
......
...@@ -6,6 +6,7 @@ from django.apps import apps ...@@ -6,6 +6,7 @@ from django.apps import apps
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.backends.db import SessionStore from django.contrib.sessions.backends.db import SessionStore
from django.db.models import Count 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 django.test import TestCase, override_settings
from .models import ( from .models import (
...@@ -233,7 +234,6 @@ class DeferRegressionTest(TestCase): ...@@ -233,7 +234,6 @@ class DeferRegressionTest(TestCase):
self.assertEqual(len(qs), 1) 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
new_class = deferred_class_factory( new_class = deferred_class_factory(
Item, Item,
('this_is_some_very_long_attribute_name_so_modelname_truncation_is_triggered',)) ('this_is_some_very_long_attribute_name_so_modelname_truncation_is_triggered',))
...@@ -241,6 +241,17 @@ class DeferRegressionTest(TestCase): ...@@ -241,6 +241,17 @@ class DeferRegressionTest(TestCase):
new_class.__name__, new_class.__name__,
'Item_Deferred_this_is_some_very_long_attribute_nac34b1f495507dad6b02e2cb235c875e') '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): class DeferAnnotateSelectRelatedTest(TestCase):
def test_defer_annotate_select_related(self): def test_defer_annotate_select_related(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment