3

In a project I'm working on, we run some tests against snapshots of production databases. For changes including migrations, I'd like to apply the migrations, run the tests, and the reverse the migrations.

However, not all migrations are reversible. How can I have an automated process detect whether all required migrations are reversible before applying them?

taleinat
  • 8,441
  • 1
  • 30
  • 44
  • A migration is reversible if *all* subparts are reversible. Generic functions are *not* reversible (in general), but things like `AddField` are. So per type of subpart, you can define the opposite, given that is possible. – Willem Van Onsem May 31 '18 at 14:58

1 Answers1

1

After a few days with no answer, I went ahead and figured out a solution. This SO answer was a good starting point.

from django.db.migrations.executor import MigrationExecutor
from django.db import connections, DEFAULT_DB_ALIAS

def are_migrations_reversible(target_migrations, database=DEFAULT_DB_ALIAS):
    """check if all migrations required to reach the target migrations are reversible

    `target_migrations` is an iterable of (app_label, migration_name) 2-tuples.
    """
    connection = connections[database]
    connection.prepare_database()
    executor = MigrationExecutor(connection)
    migration_plan = executor.migration_plan(list(target_migrations))

    return all(
        operation.reversible
        for (migration, is_backwards) in migration_plan
        for operation in migration.operations
    )

The above requires figuring out the target migrations, which can easily be extracted from the output of the showmigrations management command, or with some more effort with further use of the internal Django migrations code.

taleinat
  • 8,441
  • 1
  • 30
  • 44