Loading django/db/models/query_utils.py +5 −4 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ from __future__ import unicode_literals import inspect from collections import namedtuple from django.apps import apps from django.core.exceptions import FieldDoesNotExist from django.db.backends import utils from django.db.models.constants import LOOKUP_SEP Loading Loading @@ -272,12 +271,13 @@ def deferred_class_factory(model, attrs): """ if not attrs: return model opts = model._meta # 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 model = opts.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 Loading @@ -286,13 +286,14 @@ def deferred_class_factory(model, attrs): name = utils.truncate_name(name, 80, 32) try: return apps.get_model(model._meta.app_label, name) return opts.apps.get_model(model._meta.app_label, name) except LookupError: class Meta: proxy = True app_label = model._meta.app_label apps = opts.apps app_label = opts.app_label overrides = {attr: DeferredAttribute(attr, model) for attr in attrs} overrides["Meta"] = Meta Loading docs/releases/1.8.6.txt +9 −0 Original line number Diff line number Diff line Loading @@ -25,3 +25,12 @@ Bugfixes * Allowed filtering over a ``RawSQL`` annotation (:ticket:`25506`). * Made the ``Concat`` database function idempotent on SQLite (:ticket:`25517`). * Avoided a confusing stack trace when starting :djadmin:`runserver` with an invalid :setting:`INSTALLED_APPS` setting (:ticket:`25510`). This regression appeared in 1.8.5 as a side effect of fixing :ticket:`24704`. * Made deferred models use their proxied model's ``_meta.apps`` for caching and retrieval (:ticket:`25563`). This prevents any models generated in data migrations using ``QuerySet.defer()`` from leaking to test and application code. tests/defer_regress/tests.py +20 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,10 @@ from __future__ import unicode_literals from operator import attrgetter from django.apps import apps from django.apps.registry import Apps from django.contrib.contenttypes.models import ContentType from django.contrib.sessions.backends.db import SessionStore from django.db import models from django.db.models import Count from django.db.models.query_utils import ( DeferredAttribute, deferred_class_factory, Loading Loading @@ -263,6 +265,24 @@ class DeferRegressionTest(TestCase): deferred_cls = deferred_class_factory(Item, ()) self.assertFalse(deferred_cls._deferred) def test_deferred_class_factory_apps_reuse(self): """ #25563 - model._meta.apps should be used for caching and retrieval of the created proxy class. """ isolated_apps = Apps(['defer_regress']) class BaseModel(models.Model): field = models.BooleanField() class Meta: apps = isolated_apps app_label = 'defer_regress' deferred_model = deferred_class_factory(BaseModel, ['field']) self.assertIs(deferred_model._meta.apps, isolated_apps) self.assertIs(deferred_class_factory(BaseModel, ['field']), deferred_model) class DeferAnnotateSelectRelatedTest(TestCase): def test_defer_annotate_select_related(self): Loading Loading
django/db/models/query_utils.py +5 −4 Original line number Diff line number Diff line Loading @@ -10,7 +10,6 @@ from __future__ import unicode_literals import inspect from collections import namedtuple from django.apps import apps from django.core.exceptions import FieldDoesNotExist from django.db.backends import utils from django.db.models.constants import LOOKUP_SEP Loading Loading @@ -272,12 +271,13 @@ def deferred_class_factory(model, attrs): """ if not attrs: return model opts = model._meta # 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 model = opts.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 Loading @@ -286,13 +286,14 @@ def deferred_class_factory(model, attrs): name = utils.truncate_name(name, 80, 32) try: return apps.get_model(model._meta.app_label, name) return opts.apps.get_model(model._meta.app_label, name) except LookupError: class Meta: proxy = True app_label = model._meta.app_label apps = opts.apps app_label = opts.app_label overrides = {attr: DeferredAttribute(attr, model) for attr in attrs} overrides["Meta"] = Meta Loading
docs/releases/1.8.6.txt +9 −0 Original line number Diff line number Diff line Loading @@ -25,3 +25,12 @@ Bugfixes * Allowed filtering over a ``RawSQL`` annotation (:ticket:`25506`). * Made the ``Concat`` database function idempotent on SQLite (:ticket:`25517`). * Avoided a confusing stack trace when starting :djadmin:`runserver` with an invalid :setting:`INSTALLED_APPS` setting (:ticket:`25510`). This regression appeared in 1.8.5 as a side effect of fixing :ticket:`24704`. * Made deferred models use their proxied model's ``_meta.apps`` for caching and retrieval (:ticket:`25563`). This prevents any models generated in data migrations using ``QuerySet.defer()`` from leaking to test and application code.
tests/defer_regress/tests.py +20 −0 Original line number Diff line number Diff line Loading @@ -3,8 +3,10 @@ from __future__ import unicode_literals from operator import attrgetter from django.apps import apps from django.apps.registry import Apps from django.contrib.contenttypes.models import ContentType from django.contrib.sessions.backends.db import SessionStore from django.db import models from django.db.models import Count from django.db.models.query_utils import ( DeferredAttribute, deferred_class_factory, Loading Loading @@ -263,6 +265,24 @@ class DeferRegressionTest(TestCase): deferred_cls = deferred_class_factory(Item, ()) self.assertFalse(deferred_cls._deferred) def test_deferred_class_factory_apps_reuse(self): """ #25563 - model._meta.apps should be used for caching and retrieval of the created proxy class. """ isolated_apps = Apps(['defer_regress']) class BaseModel(models.Model): field = models.BooleanField() class Meta: apps = isolated_apps app_label = 'defer_regress' deferred_model = deferred_class_factory(BaseModel, ['field']) self.assertIs(deferred_model._meta.apps, isolated_apps) self.assertIs(deferred_class_factory(BaseModel, ['field']), deferred_model) class DeferAnnotateSelectRelatedTest(TestCase): def test_defer_annotate_select_related(self): Loading