Browse Source

Enforced unicity of app labels.

Fixed #21679.
Aymeric Augustin 11 years ago
parent
commit
63137a8304
4 changed files with 36 additions and 8 deletions
  1. 5 1
      django/apps/registry.py
  2. 16 7
      docs/releases/1.7.txt
  3. 4 0
      tests/apps/apps.py
  4. 11 0
      tests/apps/tests.py

+ 5 - 1
django/apps/registry.py

@@ -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.

+ 16 - 7
docs/releases/1.7.txt

@@ -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
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 

+ 4 - 0
tests/apps/apps.py

@@ -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'

+ 11 - 0
tests/apps/tests.py

@@ -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.