summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Holtermann <info@markusholtermann.eu>2016-11-06 13:20:08 +0100
committerTim Graham <timograham@gmail.com>2017-01-17 08:12:53 -0500
commit46e0335583661507f1c10adb97fbd9dcfbb9b787 (patch)
treee5f86a9f3290f08cb45cab91126ec88c26175966
parent45ded053b1f4320284aa5dac63052f6d1baefea9 (diff)
Refs #27666 -- Added ProjectState.reload_models().
-rw-r--r--django/db/migrations/operations/models.py5
-rw-r--r--django/db/migrations/state.py124
2 files changed, 74 insertions, 55 deletions
diff --git a/django/db/migrations/operations/models.py b/django/db/migrations/operations/models.py
index 9ad3a8a321..16cadc7a2f 100644
--- a/django/db/migrations/operations/models.py
+++ b/django/db/migrations/operations/models.py
@@ -306,6 +306,7 @@ class RenameModel(ModelOperation):
# Repoint all fields pointing to the old model to the new one.
old_model_tuple = app_label, self.old_name_lower
new_remote_model = '%s.%s' % (app_label, self.new_name)
+ to_reload = []
for (model_app_label, model_name), model_state in state.models.items():
model_changed = False
for index, (name, field) in enumerate(model_state.fields):
@@ -331,7 +332,9 @@ class RenameModel(ModelOperation):
model_state.fields[index] = name, changed_field
model_changed = True
if model_changed:
- state.reload_model(model_app_label, model_name, delay=True)
+ to_reload.append((model_app_label, model_name))
+ # Reload models related to old model before removing the old model.
+ state.reload_models(to_reload, delay=True)
# Remove the old model.
state.remove_model(app_label, self.old_name_lower)
state.reload_model(app_label, self.new_name_lower, delay=True)
diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py
index f659153a15..e44f737106 100644
--- a/django/db/migrations/state.py
+++ b/django/db/migrations/state.py
@@ -112,75 +112,91 @@ class ProjectState(object):
# the cache automatically (#24513)
self.apps.clear_cache()
- def reload_model(self, app_label, model_name, delay=False):
+ def _find_reload_model(self, app_label, model_name, delay=False):
if delay:
self.is_delayed = True
- if 'apps' in self.__dict__: # hasattr would cache the property
+ related_models = set()
+
+ try:
+ old_model = self.apps.get_model(app_label, model_name)
+ except LookupError:
+ pass
+ else:
+ # Get all relations to and from the old model before reloading,
+ # as _meta.apps may change
+ if delay:
+ related_models = get_related_models_tuples(old_model)
+ else:
+ related_models = get_related_models_recursive(old_model)
+
+ # Get all outgoing references from the model to be rendered
+ model_state = self.models[(app_label, model_name)]
+ # Directly related models are the models pointed to by ForeignKeys,
+ # OneToOneFields, and ManyToManyFields.
+ direct_related_models = set()
+ for name, field in model_state.fields:
+ if field.is_relation:
+ if field.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT:
+ continue
+ rel_app_label, rel_model_name = _get_app_label_and_model_name(field.related_model, app_label)
+ direct_related_models.add((rel_app_label, rel_model_name.lower()))
+
+ # For all direct related models recursively get all related models.
+ related_models.update(direct_related_models)
+ for rel_app_label, rel_model_name in direct_related_models:
try:
- old_model = self.apps.get_model(app_label, model_name)
+ rel_model = self.apps.get_model(rel_app_label, rel_model_name)
except LookupError:
- related_models = set()
+ pass
else:
- # Get all relations to and from the old model before reloading,
- # as _meta.apps may change
if delay:
- related_models = get_related_models_tuples(old_model)
+ related_models.update(get_related_models_tuples(rel_model))
else:
- related_models = get_related_models_recursive(old_model)
+ related_models.update(get_related_models_recursive(rel_model))
- # Get all outgoing references from the model to be rendered
- model_state = self.models[(app_label, model_name)]
- # Directly related models are the models pointed to by ForeignKeys,
- # OneToOneFields, and ManyToManyFields.
- direct_related_models = set()
- for name, field in model_state.fields:
- if field.is_relation:
- if field.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT:
- continue
- rel_app_label, rel_model_name = _get_app_label_and_model_name(field.related_model, app_label)
- direct_related_models.add((rel_app_label, rel_model_name.lower()))
+ # Include the model itself
+ related_models.add((app_label, model_name))
- # For all direct related models recursively get all related models.
- related_models.update(direct_related_models)
- for rel_app_label, rel_model_name in direct_related_models:
- try:
- rel_model = self.apps.get_model(rel_app_label, rel_model_name)
- except LookupError:
- pass
- else:
- if delay:
- related_models.update(get_related_models_tuples(rel_model))
- else:
- related_models.update(get_related_models_recursive(rel_model))
+ return related_models
- # Include the model itself
- related_models.add((app_label, model_name))
-
- # Unregister all related models
- with self.apps.bulk_update():
- for rel_app_label, rel_model_name in related_models:
- self.apps.unregister_model(rel_app_label, rel_model_name)
+ def reload_model(self, app_label, model_name, delay=False):
+ if 'apps' in self.__dict__: # hasattr would cache the property
+ related_models = self._find_reload_model(app_label, model_name, delay)
+ self._reload(related_models)
- states_to_be_rendered = []
- # Gather all models states of those models that will be rerendered.
- # This includes:
- # 1. All related models of unmigrated apps
- for model_state in self.apps.real_models:
- if (model_state.app_label, model_state.name_lower) in related_models:
- states_to_be_rendered.append(model_state)
+ def reload_models(self, models, delay=True):
+ if 'apps' in self.__dict__: # hasattr would cache the property
+ related_models = set()
+ for app_label, model_name in models:
+ related_models.update(self._find_reload_model(app_label, model_name, delay))
+ self._reload(related_models)
- # 2. All related models of migrated apps
+ def _reload(self, related_models):
+ # Unregister all related models
+ with self.apps.bulk_update():
for rel_app_label, rel_model_name in related_models:
- try:
- model_state = self.models[rel_app_label, rel_model_name]
- except KeyError:
- pass
- else:
- states_to_be_rendered.append(model_state)
+ self.apps.unregister_model(rel_app_label, rel_model_name)
+
+ states_to_be_rendered = []
+ # Gather all models states of those models that will be rerendered.
+ # This includes:
+ # 1. All related models of unmigrated apps
+ for model_state in self.apps.real_models:
+ if (model_state.app_label, model_state.name_lower) in related_models:
+ states_to_be_rendered.append(model_state)
+
+ # 2. All related models of migrated apps
+ for rel_app_label, rel_model_name in related_models:
+ try:
+ model_state = self.models[rel_app_label, rel_model_name]
+ except KeyError:
+ pass
+ else:
+ states_to_be_rendered.append(model_state)
- # Render all models
- self.apps.render_multiple(states_to_be_rendered)
+ # Render all models
+ self.apps.render_multiple(states_to_be_rendered)
def clone(self):
"Returns an exact copy of this ProjectState"