Load migration files from disk and their status from the database. Migration files are expected to live in the "migrations" directory of an app. Their names are entirely unimportant from a code perspective, but will probably follow the 1234_name.py convention. On initializatio
| 19 | |
| 20 | |
| 21 | class MigrationLoader: |
| 22 | """ |
| 23 | Load migration files from disk and their status from the database. |
| 24 | |
| 25 | Migration files are expected to live in the "migrations" directory of |
| 26 | an app. Their names are entirely unimportant from a code perspective, |
| 27 | but will probably follow the 1234_name.py convention. |
| 28 | |
| 29 | On initialization, this class will scan those directories, and open and |
| 30 | read the Python files, looking for a class called Migration, which should |
| 31 | inherit from django.db.migrations.Migration. See |
| 32 | django.db.migrations.migration for what that looks like. |
| 33 | |
| 34 | Some migrations will be marked as "replacing" another set of migrations. |
| 35 | These are loaded into a separate set of migrations away from the main ones. |
| 36 | If all the migrations they replace are either unapplied or missing from |
| 37 | disk, then they are injected into the main set, replacing the named |
| 38 | migrations. Any dependency pointers to the replaced migrations are |
| 39 | re-pointed to the new migration. |
| 40 | |
| 41 | This does mean that this class MUST also talk to the database as well as |
| 42 | to disk, but this is probably fine. We're already not just operating |
| 43 | in memory. |
| 44 | """ |
| 45 | |
| 46 | def __init__( |
| 47 | self, |
| 48 | connection, |
| 49 | load=True, |
| 50 | ignore_no_migrations=False, |
| 51 | replace_migrations=True, |
| 52 | ): |
| 53 | self.connection = connection |
| 54 | self.disk_migrations = None |
| 55 | self.applied_migrations = None |
| 56 | self.ignore_no_migrations = ignore_no_migrations |
| 57 | self.replace_migrations = replace_migrations |
| 58 | if load: |
| 59 | self.build_graph() |
| 60 | |
| 61 | @classmethod |
| 62 | def migrations_module(cls, app_label): |
| 63 | """ |
| 64 | Return the path to the migrations module for the specified app_label |
| 65 | and a boolean indicating if the module is specified in |
| 66 | settings.MIGRATION_MODULE. |
| 67 | """ |
| 68 | if app_label in settings.MIGRATION_MODULES: |
| 69 | return settings.MIGRATION_MODULES[app_label], True |
| 70 | else: |
| 71 | app_package_name = apps.get_app_config(app_label).name |
| 72 | return "%s.%s" % (app_package_name, MIGRATIONS_MODULE_NAME), False |
| 73 | |
| 74 | def load_disk(self): |
| 75 | """Load the migrations from all INSTALLED_APPS from disk.""" |
| 76 | self.disk_migrations = {} |
| 77 | self.unmigrated_apps = set() |
| 78 | self.migrated_apps = set() |
no outgoing calls