Loading django/apps/registry.py +21 −0 Original line number Diff line number Diff line Loading @@ -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 Loading django/db/migrations/state.py +1 −3 Original line number Diff line number Diff line Loading @@ -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 Loading django/db/models/base.py +26 −14 Original line number Diff line number Diff line Loading @@ -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'. Loading @@ -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 = {} Loading docs/ref/applications.txt +19 −10 Original line number Diff line number Diff line Loading @@ -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 Loading docs/releases/1.7.txt +3 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
django/apps/registry.py +21 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
django/db/migrations/state.py +1 −3 Original line number Diff line number Diff line Loading @@ -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 Loading
django/db/models/base.py +26 −14 Original line number Diff line number Diff line Loading @@ -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'. Loading @@ -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 = {} Loading
docs/ref/applications.txt +19 −10 Original line number Diff line number Diff line Loading @@ -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 Loading
docs/releases/1.7.txt +3 −0 Original line number Diff line number Diff line Loading @@ -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