Commit 63137a83 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Enforced unicity of app labels.

Fixed #21679.
parent c40209dc
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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.