Commit c40209dc authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Made it possible to change an application's label in its configuration.

Fixed #21683.
parent 5dfec4e2
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -201,6 +201,27 @@ class Apps(object):
        app_config = self.app_configs.get(app_name.rpartition(".")[2])
        return app_config is not None and app_config.name == app_name

    def get_containing_app_config(self, object_name):
        """
        Look for an app config containing a given object.

        object_name is the dotted Python path to the object.

        Returns the app config for the inner application in case of nesting.
        Returns None if the object isn't in any registered app config.

        It's safe to call this method at import time, even while the registry
        is being populated.
        """
        candidates = []
        for app_config in self.app_configs.values():
            if object_name.startswith(app_config.name):
                subpath = object_name[len(app_config.name):]
                if subpath == '' or subpath[0] == '.':
                    candidates.append(app_config)
        if candidates:
            return sorted(candidates, key=lambda ac: -len(ac.name))[0]

    def get_registered_model(self, app_label, model_name):
        """
        Similar to get_model(), but doesn't require that an app exists with
+1 −3
Original line number Diff line number Diff line
@@ -76,9 +76,7 @@ class AppConfigStub(AppConfig):
    Stubs a Django AppConfig. Only provides a label and a dict of models.
    """
    def __init__(self, label):
        self.label = label
        self.path = None
        super(AppConfigStub, self).__init__(None, None)
        super(AppConfigStub, self).__init__(label, None)

    def import_models(self, all_models):
        self.models = all_models
+26 −14
Original line number Diff line number Diff line
@@ -86,10 +86,18 @@ class ModelBase(type):
            meta = attr_meta
        base_meta = getattr(new_class, '_meta', None)

        # Look for an application configuration to attach the model to.
        app_config = apps.get_containing_app_config(module)

        if getattr(meta, 'app_label', None) is None:
            # Figure out the app_label by looking one level up from the package
            # or module named 'models'. If no such package or module exists,
            # fall back to looking one level up from the module this model is

            if app_config is None:
                # If the model is imported before the configuration for its
                # application is created (#21719), or isn't in an installed
                # application (#21680), use the legacy logic to figure out the
                # app_label by looking one level up from the package or module
                # named 'models'. If no such package or module exists, fall
                # back to looking one level up from the module this model is
                # defined in.

                # For 'django.contrib.sites.models', this would be 'sites'.
@@ -103,6 +111,10 @@ class ModelBase(type):
                except ValueError:
                    app_label_index = 1
                kwargs = {"app_label": package_components[app_label_index]}

            else:
                kwargs = {"app_label": app_config.label}

        else:
            kwargs = {}

+19 −10
Original line number Diff line number Diff line
@@ -114,24 +114,33 @@ Application configuration
Configurable attributes
-----------------------

.. attribute:: AppConfig.verbose_name
.. attribute:: AppConfig.name

    Human-readable name for the application, e.g. "Admin".
    Full Python path to the application, e.g. ``'django.contrib.admin'``.

    If this isn't provided, Django uses ``label.title()``.
    This attribute defines which application the configuration applies to. It
    must be set in all :class:`~django.apps.AppConfig` subclasses.

Read-only attributes
--------------------
    It must be unique across a Django project.

.. attribute:: AppConfig.name
.. attribute:: AppConfig.label

    Full Python path to the application, e.g. ``'django.contrib.admin'``.
    Short name for the application, e.g. ``'admin'``

.. attribute:: AppConfig.label
    This attribute allows relabelling an application when two applications
    have conflicting labels. It defaults to the last component of ``name``.
    It should be a valid Python identifier.

    It must be unique across a Django project.

.. attribute:: AppConfig.verbose_name

    Last component of the Python path to the application, e.g. ``'admin'``.
    Human-readable name for the application, e.g. "Admin".

    This attribute defaults to ``label.title()``.

    This value must be unique across a Django project.
Read-only attributes
--------------------

.. attribute:: AppConfig.path

+3 −0
Original line number Diff line number Diff line
@@ -79,6 +79,9 @@ Improvements thus far include:
* It is possible to omit ``models.py`` entirely if an application doesn't
  have any models.

* Applications can be relabeled with the :attr:`~django.apps.AppConfig.label`
  attribute of application configurations, to work around label conflicts.

* The name of applications can be customized in the admin with the
  :attr:`~django.apps.AppConfig.verbose_name` of application configurations.

Loading