Commit f91a0462 authored by Pankrat's avatar Pankrat Committed by Tim Graham
Browse files

Fixed #25833 -- Added support for non-atomic migrations.

Added the Migration.atomic attribute which can be set to False
for non-atomic migrations.
parent 0edb8a14
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -51,6 +51,9 @@ class Command(BaseCommand):
                migration_name, app_label))
        targets = [(app_label, migration.name)]

        # Show begin/end around output only for atomic migrations
        self.output_transaction = migration.atomic

        # Make a plan that represents just the requested migrations and show SQL
        # for it
        plan = [(executor.loader.graph.nodes[targets[0]], options['backwards'])]
+4 −3
Original line number Diff line number Diff line
@@ -69,17 +69,18 @@ class BaseDatabaseSchemaEditor(object):
    sql_create_pk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s PRIMARY KEY (%(columns)s)"
    sql_delete_pk = "ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"

    def __init__(self, connection, collect_sql=False):
    def __init__(self, connection, collect_sql=False, atomic=True):
        self.connection = connection
        self.collect_sql = collect_sql
        if self.collect_sql:
            self.collected_sql = []
        self.atomic_migration = self.connection.features.can_rollback_ddl and atomic

    # State-managing methods

    def __enter__(self):
        self.deferred_sql = []
        if self.connection.features.can_rollback_ddl:
        if self.atomic_migration:
            self.atomic = atomic(self.connection.alias)
            self.atomic.__enter__()
        return self
@@ -88,7 +89,7 @@ class BaseDatabaseSchemaEditor(object):
        if exc_type is None:
            for sql in self.deferred_sql:
                self.execute(sql)
        if self.connection.features.can_rollback_ddl:
        if self.atomic_migration:
            self.atomic.__exit__(exc_type, exc_value, traceback)

    # Core utility functions
+3 −3
Original line number Diff line number Diff line
@@ -170,7 +170,7 @@ class MigrationExecutor(object):
        statements = []
        state = None
        for migration, backwards in plan:
            with self.connection.schema_editor(collect_sql=True) as schema_editor:
            with self.connection.schema_editor(collect_sql=True, atomic=migration.atomic) as schema_editor:
                if state is None:
                    state = self.loader.project_state((migration.app_label, migration.name), at_end=False)
                if not backwards:
@@ -194,7 +194,7 @@ class MigrationExecutor(object):
                    fake = True
            if not fake:
                # Alright, do it normally
                with self.connection.schema_editor() as schema_editor:
                with self.connection.schema_editor(atomic=migration.atomic) as schema_editor:
                    state = migration.apply(state, schema_editor)
        # For replacement migrations, record individual statuses
        if migration.replaces:
@@ -214,7 +214,7 @@ class MigrationExecutor(object):
        if self.progress_callback:
            self.progress_callback("unapply_start", migration, fake)
        if not fake:
            with self.connection.schema_editor() as schema_editor:
            with self.connection.schema_editor(atomic=migration.atomic) as schema_editor:
                state = migration.unapply(state, schema_editor)
        # For replacement migrations, record individual statuses
        if migration.replaces:
+8 −2
Original line number Diff line number Diff line
@@ -48,6 +48,10 @@ class Migration(object):
    # introspection. If False, never perform introspection.
    initial = None

    # Whether to wrap the whole migration in a transaction. Only has an effect
    # on database backends which support transactional DDL.
    atomic = True

    def __init__(self, name, app_label):
        self.name = name
        self.app_label = app_label
@@ -114,8 +118,10 @@ class Migration(object):
            old_state = project_state.clone()
            operation.state_forwards(self.app_label, project_state)
            # Run the operation
            if not schema_editor.connection.features.can_rollback_ddl and operation.atomic:
                # We're forcing a transaction on a non-transactional-DDL backend
            atomic_operation = operation.atomic or (self.atomic and operation.atomic is not False)
            if not schema_editor.atomic_migration and atomic_operation:
                # Force a transaction on a non-transactional-DDL backend or an
                # atomic operation inside a non-atomic migration.
                with atomic(schema_editor.connection.alias):
                    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
            else:
+2 −2
Original line number Diff line number Diff line
@@ -139,7 +139,7 @@ class RunPython(Operation):

    reduces_to_sql = False

    def __init__(self, code, reverse_code=None, atomic=True, hints=None, elidable=False):
    def __init__(self, code, reverse_code=None, atomic=None, hints=None, elidable=False):
        self.atomic = atomic
        # Forwards code
        if not callable(code):
@@ -161,7 +161,7 @@ class RunPython(Operation):
        }
        if self.reverse_code is not None:
            kwargs['reverse_code'] = self.reverse_code
        if self.atomic is not True:
        if self.atomic is not None:
            kwargs['atomic'] = self.atomic
        if self.hints:
            kwargs['hints'] = self.hints
Loading