summaryrefslogtreecommitdiff
path: root/django/apps
diff options
context:
space:
mode:
authorAlex Hill <alex@hill.net.au>2016-05-18 23:18:40 +0800
committerTim Graham <timograham@gmail.com>2016-05-19 21:33:36 -0400
commit2ff7ef15b0a1d41e3f121e96cb72a383863046c0 (patch)
treeaebb17708c121fc4acf3611f9d23c69ccdc3dc7c /django/apps
parent0eac5535f7afd2295b1db978dffb97d79030807e (diff)
Refs #26421 -- Refactored Apps.lazy_model_operation() for better checks and tests
Diffstat (limited to 'django/apps')
-rw-r--r--django/apps/registry.py46
1 files changed, 26 insertions, 20 deletions
diff --git a/django/apps/registry.py b/django/apps/registry.py
index 7ed6e5d468..8a45830ccf 100644
--- a/django/apps/registry.py
+++ b/django/apps/registry.py
@@ -372,29 +372,35 @@ class Apps(object):
The function passed to this method must accept exactly n models as
arguments, where n=len(model_keys).
"""
- # If this function depends on more than one model, we recursively turn
- # it into a chain of functions that accept a single model argument and
- # pass each in turn to lazy_model_operation.
- model_key, more_models = model_keys[0], model_keys[1:]
- if more_models:
- supplied_fn = function
+ # Base case: no arguments, just execute the function.
+ if not model_keys:
+ function()
+ # Recursive case: take the head of model_keys, wait for the
+ # corresponding model class to be imported and registered, then apply
+ # that argument to the supplied function. Pass the resulting partial
+ # to lazy_model_operation() along with the remaining model args and
+ # repeat until all models are loaded and all arguments are applied.
+ else:
+ next_model, more_models = model_keys[0], model_keys[1:]
- def function(model):
- next_function = partial(supplied_fn, model)
- # Annotate the function with its field for retrieval in
- # migrations.state.StateApps.
- if getattr(supplied_fn, 'keywords', None):
- next_function.field = supplied_fn.keywords.get('field')
+ # This will be executed after the class corresponding to next_model
+ # has been imported and registered. The `func` attribute provides
+ # duck-type compatibility with partials.
+ def apply_next_model(model):
+ next_function = partial(apply_next_model.func, model)
self.lazy_model_operation(next_function, *more_models)
+ apply_next_model.func = function
- # If the model is already loaded, pass it to the function immediately.
- # Otherwise, delay execution until the class is prepared.
- try:
- model_class = self.get_registered_model(*model_key)
- except LookupError:
- self._pending_operations[model_key].append(function)
- else:
- function(model_class)
+ # If the model has already been imported and registered, partially
+ # apply it to the function now. If not, add it to the list of
+ # pending operations for the model, where it will be executed with
+ # the model class as its sole argument once the model is ready.
+ try:
+ model_class = self.get_registered_model(*next_model)
+ except LookupError:
+ self._pending_operations[next_model].append(apply_next_model)
+ else:
+ apply_next_model(model_class)
def do_pending_operations(self, model):
"""