Loading django/apps/config.py +11 −4 Original line number Diff line number Diff line from importlib import import_module import os from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured from django.utils.module_loading import module_has_submodule from django.utils._os import upath Loading Loading @@ -139,15 +139,21 @@ class AppConfig(object): # Entry is a path to an app config class. return cls(app_name, app_module) def check_models_ready(self): """ Raises an exception if models haven't been imported yet. """ if self.models is None: raise AppRegistryNotReady( "Models for app '%s' haven't been imported yet." % self.label) def get_model(self, model_name): """ Returns the model with the given case-insensitive model_name. Raises LookupError if no model exists with this name. """ if self.models is None: raise LookupError( "App '%s' doesn't have any models." % self.label) self.check_models_ready() try: return self.models[model_name.lower()] except KeyError: Loading @@ -169,6 +175,7 @@ class AppConfig(object): Set the corresponding keyword argument to True to include such models. Keyword arguments aren't documented; they're a private API. """ self.check_models_ready() for model in self.models.values(): if model._deferred and not include_deferred: continue Loading django/apps/registry.py +31 −20 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ class Apps(object): self.stored_app_configs = [] # Whether the registry is populated. self.ready = False self.apps_ready = self.models_ready = self.ready = False # Lock for thread-safe population. self._lock = threading.Lock() Loading Loading @@ -100,29 +100,41 @@ class Apps(object): "Application names aren't unique, " "duplicates: %s" % ", ".join(duplicates)) self.apps_ready = True # Load models. for app_config in self.app_configs.values(): all_models = self.all_models[app_config.label] app_config.import_models(all_models) self.clear_cache() self.ready = True self.models_ready = True for app_config in self.get_app_configs(): app_config.ready() def check_ready(self): self.ready = True def check_apps_ready(self): """ Raises an exception if the registry isn't ready. Raises an exception if all apps haven't been imported yet. """ if not self.ready: raise AppRegistryNotReady() if not self.apps_ready: raise AppRegistryNotReady("Apps aren't loaded yet.") def check_models_ready(self): """ Raises an exception if all models haven't been imported yet. """ if not self.models_ready: raise AppRegistryNotReady("Models aren't loaded yet.") def get_app_configs(self): """ Imports applications and returns an iterable of app configs. """ self.check_ready() self.check_apps_ready() return self.app_configs.values() def get_app_config(self, app_label): Loading @@ -131,7 +143,7 @@ class Apps(object): Raises LookupError if no application exists with this label. """ self.check_ready() self.check_apps_ready() try: return self.app_configs[app_label] except KeyError: Loading @@ -153,7 +165,7 @@ class Apps(object): Set the corresponding keyword argument to True to include such models. """ self.check_ready() self.check_models_ready() if app_mod: warnings.warn( "The app_mod argument of get_models is deprecated.", Loading Loading @@ -184,7 +196,7 @@ class Apps(object): model exists with this name in the application. Raises ValueError if called with a single argument that doesn't contain exactly one dot. """ self.check_ready() self.check_models_ready() if model_name is None: app_label, model_name = app_label.split('.') return self.get_app_config(app_label).get_model(model_name.lower()) Loading @@ -207,10 +219,8 @@ class Apps(object): Checks whether an application with this name exists in the registry. app_name is the full name of the app eg. 'django.contrib.admin'. It's safe to call this method at import time, even while the registry is being populated. It returns False for apps that aren't loaded yet. """ self.check_apps_ready() return any(ac.name == app_name for ac in self.app_configs.values()) def get_containing_app_config(self, object_name): Loading @@ -221,10 +231,10 @@ class Apps(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. """ # In Django 1.7 and 1.8, it's allowed to call this method at import # time, even while the registry is being populated. In Django 1.9 and # later, that should be forbidden with `self.check_apps_ready()`. candidates = [] for app_config in self.app_configs.values(): if object_name.startswith(app_config.name): Loading Loading @@ -297,10 +307,11 @@ class Apps(object): imports safely (eg. that could lead to registering listeners twice), models are registered when they're imported and never removed. """ self.check_ready() if not self.ready: raise AppRegistryNotReady("App registry isn't ready yet.") self.stored_app_configs.append(self.app_configs) self.app_configs = OrderedDict() self.ready = False self.apps_ready = self.models_ready = self.ready = False self.clear_cache() self.populate(installed) Loading @@ -309,7 +320,7 @@ class Apps(object): Cancels a previous call to set_installed_apps(). """ self.app_configs = self.stored_app_configs.pop() self.ready = True self.apps_ready = self.models_ready = self.ready = True self.clear_cache() def clear_cache(self): Loading Loading @@ -402,7 +413,7 @@ class Apps(object): warnings.warn( "[a.path for a in get_app_configs()] supersedes get_app_paths().", RemovedInDjango19Warning, stacklevel=2) self.check_ready() self.check_apps_ready() app_paths = [] for app in self.get_apps(): app_paths.append(self._get_app_path(app)) Loading docs/ref/applications.txt +6 −4 Original line number Diff line number Diff line Loading @@ -301,10 +301,6 @@ Application registry Checks whether an application with the given name exists in the registry. ``app_name`` is the full name of the app, e.g. ``'django.contrib.admin'``. Unlike :meth:`~django.apps.apps.get_app_config`, this method can be called safely at import time. If the registry is still being populated, it may return ``False``, even though the app will become available later. .. method:: apps.get_model(app_label, model_name) Returns the :class:`~django.db.models.Model` with the given ``app_label`` Loading Loading @@ -365,6 +361,9 @@ processes all applications in the order of :setting:`INSTALLED_APPS`. the order of :setting:`INSTALLED_APPS`, it's strongly recommended not import any models at this stage. Once this stage completes, APIs that operate of application configurations such as :meth:`~apps.get_app_config()` become usable. #. Then Django attempts to import the ``models`` submodule of each application, if there is one. Loading @@ -372,6 +371,9 @@ processes all applications in the order of :setting:`INSTALLED_APPS`. ``models/__init__.py``. Otherwise, the application registry may not be fully populated at this point, which could cause the ORM to malfunction. Once this stage completes, APIs that operate on models such as :meth:`~apps.get_model()` become usable. #. Finally Django runs the :meth:`~AppConfig.ready()` method of each application configuration. Loading Loading
django/apps/config.py +11 −4 Original line number Diff line number Diff line from importlib import import_module import os from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured from django.utils.module_loading import module_has_submodule from django.utils._os import upath Loading Loading @@ -139,15 +139,21 @@ class AppConfig(object): # Entry is a path to an app config class. return cls(app_name, app_module) def check_models_ready(self): """ Raises an exception if models haven't been imported yet. """ if self.models is None: raise AppRegistryNotReady( "Models for app '%s' haven't been imported yet." % self.label) def get_model(self, model_name): """ Returns the model with the given case-insensitive model_name. Raises LookupError if no model exists with this name. """ if self.models is None: raise LookupError( "App '%s' doesn't have any models." % self.label) self.check_models_ready() try: return self.models[model_name.lower()] except KeyError: Loading @@ -169,6 +175,7 @@ class AppConfig(object): Set the corresponding keyword argument to True to include such models. Keyword arguments aren't documented; they're a private API. """ self.check_models_ready() for model in self.models.values(): if model._deferred and not include_deferred: continue Loading
django/apps/registry.py +31 −20 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ class Apps(object): self.stored_app_configs = [] # Whether the registry is populated. self.ready = False self.apps_ready = self.models_ready = self.ready = False # Lock for thread-safe population. self._lock = threading.Lock() Loading Loading @@ -100,29 +100,41 @@ class Apps(object): "Application names aren't unique, " "duplicates: %s" % ", ".join(duplicates)) self.apps_ready = True # Load models. for app_config in self.app_configs.values(): all_models = self.all_models[app_config.label] app_config.import_models(all_models) self.clear_cache() self.ready = True self.models_ready = True for app_config in self.get_app_configs(): app_config.ready() def check_ready(self): self.ready = True def check_apps_ready(self): """ Raises an exception if the registry isn't ready. Raises an exception if all apps haven't been imported yet. """ if not self.ready: raise AppRegistryNotReady() if not self.apps_ready: raise AppRegistryNotReady("Apps aren't loaded yet.") def check_models_ready(self): """ Raises an exception if all models haven't been imported yet. """ if not self.models_ready: raise AppRegistryNotReady("Models aren't loaded yet.") def get_app_configs(self): """ Imports applications and returns an iterable of app configs. """ self.check_ready() self.check_apps_ready() return self.app_configs.values() def get_app_config(self, app_label): Loading @@ -131,7 +143,7 @@ class Apps(object): Raises LookupError if no application exists with this label. """ self.check_ready() self.check_apps_ready() try: return self.app_configs[app_label] except KeyError: Loading @@ -153,7 +165,7 @@ class Apps(object): Set the corresponding keyword argument to True to include such models. """ self.check_ready() self.check_models_ready() if app_mod: warnings.warn( "The app_mod argument of get_models is deprecated.", Loading Loading @@ -184,7 +196,7 @@ class Apps(object): model exists with this name in the application. Raises ValueError if called with a single argument that doesn't contain exactly one dot. """ self.check_ready() self.check_models_ready() if model_name is None: app_label, model_name = app_label.split('.') return self.get_app_config(app_label).get_model(model_name.lower()) Loading @@ -207,10 +219,8 @@ class Apps(object): Checks whether an application with this name exists in the registry. app_name is the full name of the app eg. 'django.contrib.admin'. It's safe to call this method at import time, even while the registry is being populated. It returns False for apps that aren't loaded yet. """ self.check_apps_ready() return any(ac.name == app_name for ac in self.app_configs.values()) def get_containing_app_config(self, object_name): Loading @@ -221,10 +231,10 @@ class Apps(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. """ # In Django 1.7 and 1.8, it's allowed to call this method at import # time, even while the registry is being populated. In Django 1.9 and # later, that should be forbidden with `self.check_apps_ready()`. candidates = [] for app_config in self.app_configs.values(): if object_name.startswith(app_config.name): Loading Loading @@ -297,10 +307,11 @@ class Apps(object): imports safely (eg. that could lead to registering listeners twice), models are registered when they're imported and never removed. """ self.check_ready() if not self.ready: raise AppRegistryNotReady("App registry isn't ready yet.") self.stored_app_configs.append(self.app_configs) self.app_configs = OrderedDict() self.ready = False self.apps_ready = self.models_ready = self.ready = False self.clear_cache() self.populate(installed) Loading @@ -309,7 +320,7 @@ class Apps(object): Cancels a previous call to set_installed_apps(). """ self.app_configs = self.stored_app_configs.pop() self.ready = True self.apps_ready = self.models_ready = self.ready = True self.clear_cache() def clear_cache(self): Loading Loading @@ -402,7 +413,7 @@ class Apps(object): warnings.warn( "[a.path for a in get_app_configs()] supersedes get_app_paths().", RemovedInDjango19Warning, stacklevel=2) self.check_ready() self.check_apps_ready() app_paths = [] for app in self.get_apps(): app_paths.append(self._get_app_path(app)) Loading
docs/ref/applications.txt +6 −4 Original line number Diff line number Diff line Loading @@ -301,10 +301,6 @@ Application registry Checks whether an application with the given name exists in the registry. ``app_name`` is the full name of the app, e.g. ``'django.contrib.admin'``. Unlike :meth:`~django.apps.apps.get_app_config`, this method can be called safely at import time. If the registry is still being populated, it may return ``False``, even though the app will become available later. .. method:: apps.get_model(app_label, model_name) Returns the :class:`~django.db.models.Model` with the given ``app_label`` Loading Loading @@ -365,6 +361,9 @@ processes all applications in the order of :setting:`INSTALLED_APPS`. the order of :setting:`INSTALLED_APPS`, it's strongly recommended not import any models at this stage. Once this stage completes, APIs that operate of application configurations such as :meth:`~apps.get_app_config()` become usable. #. Then Django attempts to import the ``models`` submodule of each application, if there is one. Loading @@ -372,6 +371,9 @@ processes all applications in the order of :setting:`INSTALLED_APPS`. ``models/__init__.py``. Otherwise, the application registry may not be fully populated at this point, which could cause the ORM to malfunction. Once this stage completes, APIs that operate on models such as :meth:`~apps.get_model()` become usable. #. Finally Django runs the :meth:`~AppConfig.ready()` method of each application configuration. Loading