Enforced unicity of app labels.

Fixed #21679.
This commit is contained in:
Aymeric Augustin 2013-12-31 17:25:57 +01:00
parent c40209dcc0
commit 63137a8304
4 changed files with 36 additions and 8 deletions

View File

@ -79,7 +79,11 @@ class Apps(object):
app_config = entry
else:
app_config = AppConfig.create(entry)
# TODO: check for duplicate app labels here (#21679).
if app_config.label in self.app_configs:
raise ImproperlyConfigured(
"Application labels aren't unique, "
"duplicates: %s" % app_config.label)
self.app_configs[app_config.label] = app_config
# Check for duplicate app names.

View File

@ -655,6 +655,22 @@ script with::
Otherwise, you will hit ``RuntimeError: App registry isn't ready yet.``
App registry consistency
^^^^^^^^^^^^^^^^^^^^^^^^
It is no longer possible to have multiple installed applications with the same
label. In previous versions of Django, this didn't always work correctly, but
didn't crash outright either.
If you have two apps with the same label, you should create an
:class:`~django.apps.AppConfig` for one of them and override its
:class:`~django.apps.AppConfig.label` there. You should then adjust your code
wherever it references this application or its models with the old label.
You should make sure that your project doesn't import models from applications
that aren't in :setting:`INSTALLED_APPS`. Relations involving such models may
not be created properly. Future versions of Django may forbid this entirely.
Subclassing AppCommand
^^^^^^^^^^^^^^^^^^^^^^
@ -663,13 +679,6 @@ Subclasses of :class:`~django.core.management.AppCommand` must now implement a
``handle_app()``. This method receives an :class:`~django.apps.AppConfig`
instance instead of a models module.
App registry consistency
^^^^^^^^^^^^^^^^^^^^^^^^
You should make sure that your project doesn't import models from applications
that aren't in :setting:`INSTALLED_APPS`. Relations involving such models may
not be created properly.
Introspecting applications
^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -25,6 +25,10 @@ class NoSuchApp(AppConfig):
name = 'there is no such app'
class PlainAppsConfig(AppConfig):
name = 'apps'
class RelabeledAppsConfig(AppConfig):
name = 'apps'
label = 'relabeled'

View File

@ -5,6 +5,7 @@ from django.apps.registry import Apps
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.test import TestCase, override_settings
from django.utils import six
from .models import TotallyNormal, SoAlternative, new_apps
@ -115,6 +116,16 @@ class AppsTests(TestCase):
def test_relabeling(self):
self.assertEqual(apps.get_app_config('relabeled').name, 'apps')
def test_duplicate_labels(self):
with six.assertRaisesRegex(self, ImproperlyConfigured, "Application labels aren't unique"):
with self.settings(INSTALLED_APPS=['apps.apps.PlainAppsConfig', 'apps']):
pass
def test_duplicate_names(self):
with six.assertRaisesRegex(self, ImproperlyConfigured, "Application names aren't unique"):
with self.settings(INSTALLED_APPS=['apps.apps.RelabeledAppsConfig', 'apps']):
pass
def test_models_py(self):
"""
Tests that the models in the models.py file were loaded correctly.