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.
This commit is contained in:
Aymeric Augustin 2016-05-03 12:21:54 +02:00 committed by Tim Graham
parent fd748c42a9
commit 625cd5bcb3
4 changed files with 49 additions and 9 deletions

View File

@ -155,13 +155,16 @@ class AppConfig(object):
# Entry is a path to an app config class. # Entry is a path to an app config class.
return cls(app_name, app_module) 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. Returns the model with the given case-insensitive model_name.
Raises LookupError if no model exists with this 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: try:
return self.models[model_name.lower()] return self.models[model_name.lower()]
except KeyError: except KeyError:

View File

@ -177,7 +177,7 @@ class Apps(object):
result.extend(list(app_config.get_models(include_auto_created, include_swapped))) result.extend(list(app_config.get_models(include_auto_created, include_swapped)))
return result 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. 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 model exists with this name in the application. Raises ValueError if
called with a single argument that doesn't contain exactly one dot. 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: if model_name is None:
app_label, model_name = app_label.split('.') 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): def register_model(self, app_label, model):
# Since this method is called when models are imported, it cannot # Since this method is called when models are imported, it cannot

View File

@ -229,14 +229,20 @@ Methods
Requires the app registry to be fully populated. 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 Returns the :class:`~django.db.models.Model` with the given
``model_name``. ``model_name`` is case-insensitive. ``model_name``. ``model_name`` is case-insensitive.
Raises :exc:`LookupError` if no such model exists in this application. 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() .. method:: AppConfig.ready()
@ -341,7 +347,7 @@ Application registry
Checks whether an application with the given name exists in the 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'``. ``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`` Returns the :class:`~django.db.models.Model` with the given ``app_label``
and ``model_name``. As a shortcut, this method also accepts a single 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 :exc:`ValueError` when called with a single argument that doesn't contain
exactly one dot. 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 <app-loading-process>`,
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: .. _app-loading-process:
Initialization process Initialization process

View File

@ -584,7 +584,8 @@ Miscellaneous
:exc:`~django.core.exceptions.AppRegistryNotReady` if they're called before :exc:`~django.core.exceptions.AppRegistryNotReady` if they're called before
models of all applications have been loaded. Previously they only required models of all applications have been loaded. Previously they only required
the target application's models to be loaded and thus could return models 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: .. _deprecated-features-1.11: