summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteadman <mark@steadman.io>2015-06-04 14:47:44 +0100
committerTim Graham <timograham@gmail.com>2015-06-04 22:35:33 -0400
commited63df3fc2f0c228354ca3435e9bed45be9d0909 (patch)
tree76efeb22f7c4a577f76160d99857ffea415ea20e
parent2dc93bb10ab1c2af1df9977f1b51d47cadab7b21 (diff)
Fixed #24899 -- Split migrations autodetector._detect_changes() method
-rw-r--r--django/db/migrations/autodetector.py122
1 files changed, 70 insertions, 52 deletions
diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
index 9a4ba42722..ddf8e36b83 100644
--- a/django/db/migrations/autodetector.py
+++ b/django/db/migrations/autodetector.py
@@ -155,9 +155,40 @@ class MigrationAutodetector(object):
# Renames have to come first
self.generate_renamed_models()
- # Prepare field lists, and prepare a list of the fields that used
- # through models in the old state so we can make dependencies
- # from the through model deletion to the field that uses it.
+ # Prepare lists of fields and generate through model map
+ self._prepare_field_lists()
+ self._generate_through_model_map()
+
+ # Generate non-rename model operations
+ self.generate_deleted_models()
+ self.generate_created_models()
+ self.generate_deleted_proxies()
+ self.generate_created_proxies()
+ self.generate_altered_options()
+ self.generate_altered_managers()
+
+ # Generate field operations
+ self.generate_renamed_fields()
+ self.generate_removed_fields()
+ self.generate_added_fields()
+ self.generate_altered_fields()
+ self.generate_altered_unique_together()
+ self.generate_altered_index_together()
+ self.generate_altered_db_table()
+ self.generate_altered_order_with_respect_to()
+
+ self._sort_migrations()
+ self._build_migration_list(graph)
+ self._optimize_migrations()
+
+ return self.migrations
+
+ def _prepare_field_lists(self):
+ """
+ Prepare field lists, and prepare a list of the fields that used
+ through models in the old state so we can make dependencies
+ from the through model deletion to the field that uses it.
+ """
self.kept_model_keys = set(self.old_model_keys).intersection(self.new_model_keys)
self.kept_proxy_keys = set(self.old_proxy_keys).intersection(self.new_proxy_keys)
self.kept_unmanaged_keys = set(self.old_unmanaged_keys).intersection(self.new_unmanaged_keys)
@@ -171,7 +202,10 @@ class MigrationAutodetector(object):
self.old_field_keys.update((app_label, model_name, x) for x, y in old_model_state.fields)
self.new_field_keys.update((app_label, model_name, x) for x, y in new_model_state.fields)
- # Through model map generation
+ def _generate_through_model_map(self):
+ """
+ Through model map generation
+ """
for app_label, model_name in sorted(self.old_model_keys):
old_model_name = self.renamed_models.get((app_label, model_name), model_name)
old_model_state = self.from_state.models[app_label, old_model_name]
@@ -185,51 +219,17 @@ class MigrationAutodetector(object):
)
self.through_users[through_key] = (app_label, old_model_name, field_name)
- # Generate non-rename model operations
- self.generate_deleted_models()
- self.generate_created_models()
- self.generate_deleted_proxies()
- self.generate_created_proxies()
- self.generate_altered_options()
- self.generate_altered_managers()
-
- # Generate field operations
- self.generate_renamed_fields()
- self.generate_removed_fields()
- self.generate_added_fields()
- self.generate_altered_fields()
- self.generate_altered_unique_together()
- self.generate_altered_index_together()
- self.generate_altered_db_table()
- self.generate_altered_order_with_respect_to()
-
- # Now, reordering to make things possible. The order we have already
- # isn't bad, but we need to pull a few things around so FKs work nicely
- # inside the same app
- for app_label, ops in sorted(self.generated_operations.items()):
-
- # construct a dependency graph for intra-app dependencies
- dependency_graph = {op: set() for op in ops}
- for op in ops:
- for dep in op._auto_deps:
- if dep[0] == app_label:
- for op2 in ops:
- if self.check_dependency(op2, dep):
- dependency_graph[op].add(op2)
-
- # we use a stable sort for deterministic tests & general behavior
- self.generated_operations[app_label] = stable_topological_sort(ops, dependency_graph)
-
- # Now, we need to chop the lists of operations up into migrations with
- # dependencies on each other.
- # We do this by stepping up an app's list of operations until we
- # find one that has an outgoing dependency that isn't in another app's
- # migration yet (hasn't been chopped off its list). We then chop off the
- # operations before it into a migration and move onto the next app.
- # If we loop back around without doing anything, there's a circular
- # dependency (which _should_ be impossible as the operations are all
- # split at this point so they can't depend and be depended on)
-
+ def _build_migration_list(self, graph=None):
+ """
+ We need to chop the lists of operations up into migrations with
+ dependencies on each other. We do this by stepping up an app's list of
+ operations until we find one that has an outgoing dependency that isn't
+ in another app's migration yet (hasn't been chopped off its list). We
+ then chop off the operations before it into a migration and move onto
+ the next app. If we loop back around without doing anything, there's a
+ circular dependency (which _should_ be impossible as the operations are
+ all split at this point so they can't depend and be depended on).
+ """
self.migrations = {}
num_ops = sum(len(x) for x in self.generated_operations.values())
chop_mode = False
@@ -309,7 +309,27 @@ class MigrationAutodetector(object):
raise ValueError("Cannot resolve operation dependencies: %r" % self.generated_operations)
num_ops = new_num_ops
- # OK, add in internal dependencies among the migrations
+ def _sort_migrations(self):
+ """
+ Reorder to make things possible. The order we have already isn't bad,
+ but we need to pull a few things around so FKs work nicely inside the
+ same app
+ """
+ for app_label, ops in sorted(self.generated_operations.items()):
+ # construct a dependency graph for intra-app dependencies
+ dependency_graph = {op: set() for op in ops}
+ for op in ops:
+ for dep in op._auto_deps:
+ if dep[0] == app_label:
+ for op2 in ops:
+ if self.check_dependency(op2, dep):
+ dependency_graph[op].add(op2)
+
+ # we use a stable sort for deterministic tests & general behavior
+ self.generated_operations[app_label] = stable_topological_sort(ops, dependency_graph)
+
+ def _optimize_migrations(self):
+ # Add in internal dependencies among the migrations
for app_label, migrations in self.migrations.items():
for m1, m2 in zip(migrations, migrations[1:]):
m2.dependencies.append((app_label, m1.name))
@@ -324,8 +344,6 @@ class MigrationAutodetector(object):
for migration in migrations:
migration.operations = MigrationOptimizer().optimize(migration.operations, app_label=app_label)
- return self.migrations
-
def check_dependency(self, operation, dependency):
"""
Returns ``True`` if the given operation depends on the given dependency,