diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2013-12-30 15:42:15 +0100 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2013-12-30 22:11:17 +0100 |
| commit | 80d74097b4bd7186ad99b6d41d0ed90347a39b21 (patch) | |
| tree | 7b00c5113c311aaaeba4393701151e916ae7f9f0 /django/apps | |
| parent | 7ed20e015335076fc98ad805eaf241f8a0d872d5 (diff) | |
Stopped populating the app registry as a side effect.
Since it triggers imports, it shouldn't be done lightly.
This commit adds a public API for doing it explicitly, django.setup(),
and does it automatically when using manage.py and wsgi.py.
Diffstat (limited to 'django/apps')
| -rw-r--r-- | django/apps/base.py | 7 | ||||
| -rw-r--r-- | django/apps/registry.py | 44 |
2 files changed, 24 insertions, 27 deletions
diff --git a/django/apps/base.py b/django/apps/base.py index eaf8993624..ae2abaae84 100644 --- a/django/apps/base.py +++ b/django/apps/base.py @@ -114,8 +114,6 @@ class AppConfig(object): Returns the model with the given case-insensitive model_name. Raises LookupError if no model exists with this name. - - This method assumes that apps.populate_models() has run. """ if self.models is None: raise LookupError( @@ -140,8 +138,6 @@ class AppConfig(object): Set the corresponding keyword argument to True to include such models. Keyword arguments aren't documented; they're a private API. - - This method assumes that apps.populate_models() has run. """ for model in self.models.values(): if model._deferred and not include_deferred: @@ -156,7 +152,8 @@ 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 may happen before populate_models() runs. + # imported, which might happen before populate_models() runs (or at + # least used to). 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 35c4ac3cea..0e39068e1f 100644 --- a/django/apps/registry.py +++ b/django/apps/registry.py @@ -3,7 +3,6 @@ import os import sys import warnings -from django.conf import settings from django.core.exceptions import ImproperlyConfigured from django.utils import lru_cache from django.utils.module_loading import import_lock @@ -79,8 +78,6 @@ class Apps(object): # Application modules aren't expected to import anything, and # especially not other application modules, even indirectly. # Therefore we simply import them sequentially. - if installed_apps is None: - installed_apps = settings.INSTALLED_APPS for entry in installed_apps: if isinstance(entry, AppConfig): app_config = entry @@ -108,7 +105,9 @@ class Apps(object): if self._models_loaded: return - self.populate_apps() + if not self._apps_loaded: + raise RuntimeError( + "populate_models() must run after populate_apps()") # Models modules are likely to import other models modules, for # example to reference related objects. As a consequence: @@ -144,6 +143,15 @@ class Apps(object): for app_config in self.get_app_configs(): app_config.setup() + def check_ready(self): + """ + Raises an exception if the registry isn't ready. + """ + if not self._models_loaded: + raise RuntimeError( + "App registry isn't populated yet. " + "Have you called django.setup()?") + @property def ready(self): """ @@ -161,11 +169,7 @@ class Apps(object): If only_with_models_module in True (non-default), imports models and considers only applications containing a models module. """ - if only_with_models_module: - self.populate_models() - else: - self.populate_apps() - + self.check_ready() for app_config in self.app_configs.values(): if only_with_models_module and app_config.models_module is None: continue @@ -180,11 +184,7 @@ class Apps(object): If only_with_models_module in True (non-default), imports models and considers only applications containing a models module. """ - if only_with_models_module: - self.populate_models() - else: - self.populate_apps() - + self.check_ready() app_config = self.app_configs.get(app_label) if app_config is None: raise LookupError("No installed app with label '%s'." % app_label) @@ -208,8 +208,7 @@ class Apps(object): Set the corresponding keyword argument to True to include such models. """ - self.populate_models() - + self.check_ready() if app_mod: warnings.warn( "The app_mod argument of get_models is deprecated.", @@ -236,7 +235,7 @@ class Apps(object): Raises LookupError if no application exists with this label, or no model exists with this name in the application. """ - self.populate_models() + self.check_ready() return self.get_app_config(app_label).get_model(model_name.lower()) def register_model(self, app_label, model): @@ -328,7 +327,8 @@ class Apps(object): imports safely (eg. that could lead to registering listeners twice), models are registered when they're imported and never removed. """ - self.stored_app_configs.append((self.app_configs, self._apps_loaded, self._models_loaded)) + self.check_ready() + self.stored_app_configs.append(self.app_configs) self.app_configs = OrderedDict() self.clear_cache() self._apps_loaded = False @@ -340,7 +340,9 @@ class Apps(object): """ Cancels a previous call to set_installed_apps(). """ - self.app_configs, self._apps_loaded, self._models_loaded = self.stored_app_configs.pop() + self.app_configs = self.stored_app_configs.pop() + self._apps_loaded = True + self._models_loaded = True self.clear_cache() def clear_cache(self): @@ -429,9 +431,7 @@ class Apps(object): warnings.warn( "[a.path for a in get_app_configs()] supersedes get_app_paths().", PendingDeprecationWarning, stacklevel=2) - - self.populate_models() - + self.check_ready() app_paths = [] for app in self.get_apps(): app_paths.append(self._get_app_path(app)) |
