Browse Source

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.
Aymeric Augustin 9 years ago
parent
commit
625cd5bcb3
4 changed files with 49 additions and 9 deletions
  1. 5 2
      django/apps/config.py
  2. 13 3
      django/apps/registry.py
  3. 29 3
      docs/ref/applications.txt
  4. 2 1
      docs/releases/1.11.txt

+ 5 - 2
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:

+ 13 - 3
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

+ 29 - 3
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 <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:
 
 Initialization process

+ 2 - 1
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: