Commit ac576e9f authored by jMyles's avatar jMyles Committed by Tim Graham
Browse files

[1.8.x] Fixed #24287 -- Added friendly error if a model is in a models.py outside an installed app.

parent 64a95408
Loading
Loading
Loading
Loading
+24 −11
Original line number Diff line number Diff line
@@ -2,34 +2,41 @@ from __future__ import unicode_literals

import copy
import inspect
from itertools import chain
import sys
import warnings
from itertools import chain

from django.apps import apps
from django.apps.config import MODELS_MODULE_NAME
from django.conf import settings
from django.core import checks
from django.core.exceptions import (FieldDoesNotExist, ObjectDoesNotExist,
    MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS)
from django.db import (router, connections, transaction, DatabaseError,
    DEFAULT_DB_ALIAS, DJANGO_VERSION_PICKLE_KEY)
from django.core.exceptions import (
    NON_FIELD_ERRORS, FieldDoesNotExist, FieldError, ImproperlyConfigured,
    MultipleObjectsReturned, ObjectDoesNotExist, ValidationError,
)
from django.db import (
    DEFAULT_DB_ALIAS, DJANGO_VERSION_PICKLE_KEY, DatabaseError, connections,
    router, transaction,
)
from django.db.models import signals
from django.db.models.constants import LOOKUP_SEP
from django.db.models.deletion import Collector
from django.db.models.fields import AutoField
from django.db.models.fields.related import (ForeignObjectRel, ManyToOneRel,
    OneToOneField, add_lazy_relation)
from django.db.models.fields.related import (
    ForeignObjectRel, ManyToOneRel, OneToOneField, add_lazy_relation,
)
from django.db.models.manager import ensure_default_manager
from django.db.models.options import Options
from django.db.models.query import Q
from django.db.models.query_utils import DeferredAttribute, deferred_class_factory
from django.db.models.query_utils import (
    DeferredAttribute, deferred_class_factory,
)
from django.utils import six
from django.utils.deprecation import RemovedInDjango19Warning
from django.utils.encoding import force_str, force_text
from django.utils.functional import curry
from django.utils.six.moves import zip
from django.utils.text import get_text_list, capfirst
from django.utils.text import capfirst, get_text_list
from django.utils.translation import ugettext_lazy as _
from django.utils.version import get_version

@@ -115,8 +122,14 @@ class ModelBase(type):
                    app_label_index = package_components.index(MODELS_MODULE_NAME) + 1
                except ValueError:
                    app_label_index = 1
                try:
                    kwargs = {"app_label": package_components[app_label_index]}

                except IndexError:
                    raise ImproperlyConfigured(
                        'Unable to detect the app label for model "%s." '
                        'Ensure that its module, "%s", is located inside an installed '
                        'app.' % (new_class.__name__, model_module.__name__)
                    )
            else:
                kwargs = {"app_label": app_config.label}

+26 −0
Original line number Diff line number Diff line
from __future__ import unicode_literals

import os
import sys

from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.test import TestCase
from django.test.utils import extend_sys_path
from django.utils._os import upath
@@ -75,3 +78,26 @@ class GetModelsTest(TestCase):
        self.assertNotIn(
            "NotInstalledModel",
            [m.__name__ for m in apps.get_models()])

    def test_exception_raised_if_model_declared_outside_app(self):

        class FakeModule(models.Model):
            __name__ = str("models_that_do_not_live_in_an_app")

        sys.modules['models_not_in_app'] = FakeModule

        def declare_model_outside_app():
            models.base.ModelBase.__new__(
                models.base.ModelBase,
                str('Outsider'),
                (models.Model,),
                {'__module__': 'models_not_in_app'})

        msg = (
            'Unable to detect the app label for model "Outsider." '
            'Ensure that its module, "models_that_do_not_live_in_an_app", '
            'is located inside an installed app.'
        )

        with self.assertRaisesMessage(ImproperlyConfigured, msg):
            declare_model_outside_app()