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

This commit is contained in:
jMyles 2015-02-05 16:50:31 -05:00 committed by Tim Graham
parent 64a9540829
commit ac576e9f45
2 changed files with 50 additions and 11 deletions

View File

@ -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
kwargs = {"app_label": package_components[app_label_index]}
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}

View File

@ -1,8 +1,11 @@
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()