diff --git a/django/__init__.py b/django/__init__.py index 61413abe8e..69be8c9984 100644 --- a/django/__init__.py +++ b/django/__init__.py @@ -13,5 +13,4 @@ def setup(): # INSTALLED_APPS or any other setting) and populate the app registry. from django.apps import apps from django.conf import settings - apps.populate_apps(settings.INSTALLED_APPS) - apps.populate_models() + apps.populate(settings.INSTALLED_APPS) diff --git a/django/apps/base.py b/django/apps/base.py index ae2abaae84..1aa5c29fd2 100644 --- a/django/apps/base.py +++ b/django/apps/base.py @@ -152,8 +152,7 @@ class AppConfig(object): # Dictionary of models for this app, primarily maintained in the # 'all_models' attribute of the Apps this AppConfig is attached to. # Injected as a parameter because it gets populated when models are - # imported, which might happen before populate_models() runs (or at - # least used to). + # imported, which might happen before populate() imports models. self.models = all_models if module_has_submodule(self.module, MODELS_MODULE_NAME): diff --git a/django/apps/registry.py b/django/apps/registry.py index 9152e80593..a6b807e608 100644 --- a/django/apps/registry.py +++ b/django/apps/registry.py @@ -41,43 +41,39 @@ class Apps(object): # set_available_apps and set_installed_apps. self.stored_app_configs = [] - # Internal flags used when populating the registry. - self._apps_loaded = False - self._models_loaded = False + # Whether the registry is populated. + self.ready = False # Pending lookups for lazy relations. self._pending_lookups = {} # Populate apps and models, unless it's the master registry. if installed_apps is not None: - self.populate_apps(installed_apps) - self.populate_models() + self.populate(installed_apps) - def populate_apps(self, installed_apps=None): + def populate(self, installed_apps=None): """ - Populate app-related information. + Loads application configurations and models. - This method imports each application module. + This method imports each application module and then each model module. It is thread safe and idempotent, but not reentrant. """ - if self._apps_loaded: + if self.ready: return - # Since populate_apps() may be a side effect of imports, and since - # it will itself import modules, an ABBA deadlock between threads - # would be possible if we didn't take the import lock. See #18251. + # Since populate() may be a side effect of imports, and since it will + # itself import modules, an ABBA deadlock between threads would be + # possible if we didn't take the import lock. See #18251. with import_lock(): - if self._apps_loaded: + if self.ready: return # app_config should be pristine, otherwise the code below won't # guarantee that the order matches the order in INSTALLED_APPS. if self.app_configs: - raise RuntimeError("populate_apps() isn't reentrant") + raise RuntimeError("populate() isn't reentrant") - # Application modules aren't expected to import anything, and - # especially not other application modules, even indirectly. - # Therefore we simply import them sequentially. + # Load app configs and app modules. for entry in installed_apps: if isinstance(entry, AppConfig): app_config = entry @@ -85,36 +81,13 @@ class Apps(object): app_config = AppConfig.create(entry) self.app_configs[app_config.label] = app_config - self.clear_cache() - self._apps_loaded = True - - def populate_models(self): - """ - Populate model-related information. - - This method imports each models module. - - It is thread safe, idempotent and reentrant. - """ - if self._models_loaded: - return - # Since populate_models() may be a side effect of imports, and since - # it will itself import modules, an ABBA deadlock between threads - # would be possible if we didn't take the import lock. See #18251. - with import_lock(): - if self._models_loaded: - return - - if not self._apps_loaded: - raise RuntimeError( - "populate_models() must run after populate_apps()") - + # 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._models_loaded = True + self.ready = True for app_config in self.get_app_configs(): app_config.setup() @@ -123,21 +96,11 @@ class Apps(object): """ Raises an exception if the registry isn't ready. """ - if not self._models_loaded: + if not self.ready: raise RuntimeError( "App registry isn't populated yet. " "Have you called django.setup()?") - @property - def ready(self): - """ - Whether the registry is fully populated. - - Useful for code that wants to cache the results of get_models() for - themselves once it is safe to do so. - """ - return self._models_loaded # implies self._apps_loaded. - def get_app_configs(self, only_with_models_module=False): """ Imports applications and returns an iterable of app configs. @@ -306,19 +269,16 @@ class Apps(object): self.check_ready() self.stored_app_configs.append(self.app_configs) self.app_configs = OrderedDict() + self.ready = False self.clear_cache() - self._apps_loaded = False - self.populate_apps(installed) - self._models_loaded = False - self.populate_models() + self.populate(installed) def unset_installed_apps(self): """ Cancels a previous call to set_installed_apps(). """ self.app_configs = self.stored_app_configs.pop() - self._apps_loaded = True - self._models_loaded = True + self.ready = True self.clear_cache() def clear_cache(self): diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py index c9ccd6a370..2a4fd96fc7 100644 --- a/django/core/management/__init__.py +++ b/django/core/management/__init__.py @@ -121,8 +121,7 @@ def get_commands(): # avoid catching ImproperlyConfigured errors that aren't caused # by the absence of a settings module. from django.apps import apps - apps.populate_apps(installed_apps) - apps.populate_models() + apps.populate(installed_apps) app_configs = apps.get_app_configs() app_names = [app_config.name for app_config in app_configs]