From 625cd5bcb315154ed28061fefaf639aff54da7c2 Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Tue, 3 May 2016 12:21:54 +0200 Subject: [PATCH] Added require_ready argument to get_model methods. This allows bringing back the behavior of Django < 1.7. Also fixed the check for the app registry being ready in AppConfig.get_model(s), which was inconsistent with the equivalent check in Apps.get_model(s). That part is a backwards-incompatible change. --- django/apps/config.py | 7 +++++-- django/apps/registry.py | 16 +++++++++++++--- docs/ref/applications.txt | 32 +++++++++++++++++++++++++++++--- docs/releases/1.11.txt | 3 ++- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/django/apps/config.py b/django/apps/config.py index 72c51214117..14925cd1ce1 100644 --- a/django/apps/config.py +++ b/django/apps/config.py @@ -155,13 +155,16 @@ class AppConfig(object): # Entry is a path to an app config class. return cls(app_name, app_module) - def get_model(self, model_name): + def get_model(self, model_name, require_ready=True): """ Returns the model with the given case-insensitive model_name. Raises LookupError if no model exists with this name. """ - self.apps.check_models_ready() + if require_ready: + self.apps.check_models_ready() + else: + self.apps.check_apps_ready() try: return self.models[model_name.lower()] except KeyError: diff --git a/django/apps/registry.py b/django/apps/registry.py index adf6cbf7530..48694d0f2c6 100644 --- a/django/apps/registry.py +++ b/django/apps/registry.py @@ -177,7 +177,7 @@ class Apps(object): result.extend(list(app_config.get_models(include_auto_created, include_swapped))) return result - def get_model(self, app_label, model_name=None): + def get_model(self, app_label, model_name=None, require_ready=True): """ Returns the model matching the given app_label and model_name. @@ -190,10 +190,20 @@ 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_models_ready() + if require_ready: + self.check_models_ready() + else: + self.check_apps_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()) + + app_config = self.get_app_config(app_label) + + if not require_ready and app_config.models is None: + app_config.import_models() + + return app_config.get_model(model_name, require_ready=require_ready) def register_model(self, app_label, model): # Since this method is called when models are imported, it cannot diff --git a/docs/ref/applications.txt b/docs/ref/applications.txt index 110e5e867db..149312aafd6 100644 --- a/docs/ref/applications.txt +++ b/docs/ref/applications.txt @@ -229,14 +229,20 @@ Methods Requires the app registry to be fully populated. -.. method:: AppConfig.get_model(model_name) +.. method:: AppConfig.get_model(model_name, require_ready=True) Returns the :class:`~django.db.models.Model` with the given ``model_name``. ``model_name`` is case-insensitive. Raises :exc:`LookupError` if no such model exists in this application. - Requires the app registry to be fully populated. + Requires the app registry to be fully populated unless the + ``require_ready`` argument is set to ``False``. ``require_ready`` behaves + exactly as in :meth:`apps.get_model()`. + + .. versionadded:: 1.11 + + The ``require_ready`` keyword argument was added. .. method:: AppConfig.ready() @@ -341,7 +347,7 @@ 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'``. -.. method:: apps.get_model(app_label, model_name) +.. method:: apps.get_model(app_label, model_name, require_ready=True) Returns the :class:`~django.db.models.Model` with the given ``app_label`` and ``model_name``. As a shortcut, this method also accepts a single @@ -352,6 +358,26 @@ Application registry :exc:`ValueError` when called with a single argument that doesn't contain exactly one dot. + Requires the app registry to be fully populated unless the + ``require_ready`` argument is set to ``False``. + + Setting ``require_ready`` to ``False`` allows looking up models + :ref:`while the app registry is being populated `, + specifically during the second phase where it imports models. Then + ``get_model()`` has the same effect as importing the model. The main use + case is to configure model classes with settings, such as + :setting:`AUTH_USER_MODEL`. + + When ``require_ready`` is ``False``, ``get_model()`` returns a model class + that may not be fully functional (reverse accessors may be missing, for + example) until the app registry is fully populated. For this reason, it's + best to leave ``require_ready`` to the default value of ``True`` whenever + possible. + + .. versionadded:: 1.11 + + The ``require_ready`` keyword argument was added. + .. _app-loading-process: Initialization process diff --git a/docs/releases/1.11.txt b/docs/releases/1.11.txt index 8fd0795d67c..7886d84a3ba 100644 --- a/docs/releases/1.11.txt +++ b/docs/releases/1.11.txt @@ -584,7 +584,8 @@ Miscellaneous :exc:`~django.core.exceptions.AppRegistryNotReady` if they're called before models of all applications have been loaded. Previously they only required the target application's models to be loaded and thus could return models - without all their relations set up. + without all their relations set up. If you need the old behavior of + ``get_model()``, set the ``require_ready`` argument to ``False``. .. _deprecated-features-1.11: