| 35 | |
| 36 | |
| 37 | class MigrationAutodetector: |
| 38 | def __init__( |
| 39 | self, |
| 40 | apps: Apps, |
| 41 | apps_config: dict[str, dict], |
| 42 | *, |
| 43 | now: Callable[[], dt.datetime] | None = None, |
| 44 | ) -> None: |
| 45 | self.apps = apps |
| 46 | self.apps_config = apps_config |
| 47 | self._now = now or dt.datetime.now |
| 48 | self.loader = MigrationLoader(apps_config, _NoopRecorder(), load=False) |
| 49 | |
| 50 | async def changes(self) -> list[MigrationWriter]: |
| 51 | await self.loader.build_graph() |
| 52 | old_state = await self._project_state() |
| 53 | new_state = self._current_state() |
| 54 | writers: list[MigrationWriter] = [] |
| 55 | for app_label, config in self.apps_config.items(): |
| 56 | migrations_module = config.get("migrations") |
| 57 | if not migrations_module: |
| 58 | continue |
| 59 | operations = OperationGenerator(old_state, new_state).generate(app_labels=[app_label]) |
| 60 | if not operations: |
| 61 | continue |
| 62 | dependencies = self._dependencies_for_app(app_label, new_state) |
| 63 | name, initial = self._migration_name(app_label, old_state, new_state) |
| 64 | writers.append( |
| 65 | MigrationWriter( |
| 66 | name, |
| 67 | app_label, |
| 68 | operations, |
| 69 | dependencies=dependencies, |
| 70 | initial=initial, |
| 71 | migrations_module=migrations_module, |
| 72 | ) |
| 73 | ) |
| 74 | return writers |
| 75 | |
| 76 | async def write(self) -> list[str]: |
| 77 | writers = await self.changes() |
| 78 | return [str(writer.write()) for writer in writers] |
| 79 | |
| 80 | def _current_state(self) -> State: |
| 81 | state = State(models={}, apps=StateApps()) |
| 82 | for app_label, models in self.apps.items(): |
| 83 | for model in models.values(): |
| 84 | state.models[(app_label, model.__name__)] = ModelState.make_from_model( |
| 85 | app_label, model |
| 86 | ) |
| 87 | return state |
| 88 | |
| 89 | async def _project_state(self) -> State: |
| 90 | state = State(models={}, apps=StateApps()) |
| 91 | for key in self._full_plan(): |
| 92 | migration = self.loader.graph.nodes[key] |
| 93 | if not isinstance(migration, Migration): |
| 94 | raise ValueError(f"Missing migration for {key}") |
no outgoing calls
searching dependent graphs…