Given a set of targets, return a list of (Migration instance, backwards?).
(self, targets, clean_start=False)
| 20 | self.progress_callback = progress_callback |
| 21 | |
| 22 | def migration_plan(self, targets, clean_start=False): |
| 23 | """ |
| 24 | Given a set of targets, return a list of (Migration instance, |
| 25 | backwards?). |
| 26 | """ |
| 27 | plan = [] |
| 28 | if clean_start: |
| 29 | applied = {} |
| 30 | else: |
| 31 | applied = dict(self.loader.applied_migrations) |
| 32 | for target in targets: |
| 33 | # If the target is (app_label, None), that means unmigrate |
| 34 | # everything |
| 35 | if target[1] is None: |
| 36 | for root in self.loader.graph.root_nodes(): |
| 37 | if root[0] == target[0]: |
| 38 | for migration in self.loader.graph.backwards_plan(root): |
| 39 | if migration in applied: |
| 40 | plan.append((self.loader.graph.nodes[migration], True)) |
| 41 | applied.pop(migration) |
| 42 | # If the target is missing, it's likely a replaced migration. |
| 43 | # Reload the graph without replacements. |
| 44 | elif ( |
| 45 | self.loader.replace_migrations |
| 46 | and target not in self.loader.graph.node_map |
| 47 | ): |
| 48 | self.loader.replace_migrations = False |
| 49 | self.loader.build_graph() |
| 50 | return self.migration_plan(targets, clean_start=clean_start) |
| 51 | # If the migration is already applied, do backwards mode, |
| 52 | # otherwise do forwards mode. |
| 53 | elif target in applied: |
| 54 | # Don't migrate backwards all the way to the target node (that |
| 55 | # may roll back dependencies in other apps that don't need to |
| 56 | # be rolled back); instead roll back through target's immediate |
| 57 | # child(ren) in the same app, and no further. |
| 58 | next_in_app = sorted( |
| 59 | n |
| 60 | for n in self.loader.graph.node_map[target].children |
| 61 | if n[0] == target[0] |
| 62 | ) |
| 63 | for node in next_in_app: |
| 64 | for migration in self.loader.graph.backwards_plan(node): |
| 65 | if migration in applied: |
| 66 | plan.append((self.loader.graph.nodes[migration], True)) |
| 67 | applied.pop(migration) |
| 68 | else: |
| 69 | for migration in self.loader.graph.forwards_plan(target): |
| 70 | if migration not in applied: |
| 71 | plan.append((self.loader.graph.nodes[migration], False)) |
| 72 | applied[migration] = self.loader.graph.nodes[migration] |
| 73 | return plan |
| 74 | |
| 75 | def _create_project_state(self, with_applied_migrations=False): |
| 76 | """ |