the base class for all migrations migration files will import this from django db migrations migration and subclass it as a class called migration it will have one or more of the following attributes operations a list of operation instances probably from django db migrations operations dependencies a list of tuples of apppath migrationname runbefore a list of tuples of apppath migrationname replaces a list of migrationnames note that all migrations come out of migrations and into the loader or graph as instances having been initialized with their app label and name operations to apply during this migration in order other migrations that should be run before this migration should be a list of app migrationname other migrations that should be run after this one i e have this migration added to their dependencies useful to make thirdparty apps migrations run after your authuser replacement for example migration names in this app that this migration replaces if this is nonempty this migration will only be applied if all these migrations are not applied is this an initial migration initial migrations are skipped on fakeinitial if the table or fields already exist if none check if the migration has any dependencies to determine if there are dependencies to tell if db introspection needs to be done if true always perform introspection if false never perform introspection whether to wrap the whole migration in a transaction only has an effect on database backends which support transactional ddl copy dependencies other attrs as we might mutate them at runtime take a projectstate and return a new one with the migration s operations applied to it preserve the original object state by default and return a mutated state from a copy take a projectstate representing all migrations prior to this one and a schemaeditor for a live database and apply the migration in a forwards order return the resulting project state for efficient reuse by following migrations if this operation cannot be represented as sql place a comment there instead save the state before the operation has run run the operation force a transaction on a nontransactionalddl backend or an atomic operation inside a nonatomic migration normal behaviour take a projectstate representing all migrations prior to this one and a schemaeditor for a live database and apply the migration in a reverse order the backwards migration process consists of two phases 1 the intermediate states from right before the first until right after the last operation inside this migration are preserved 2 the operations are applied in reverse order using the states recorded in step 1 construct all the intermediate states we need for a reverse migration phase 1 if it s irreversible error out preserve new state from previous run to not tamper the same state over all operations phase 2 force a transaction on a nontransactionalddl backend or an atomic operation inside a nonatomic migration normal behaviour suggest a name for the operations this migration might represent names are not guaranteed to be unique but put some effort into the fallback name to avoid vcs conflicts if possible subclass of tuple so django can tell this was originally a swappable dependency when it reads the migration file turn a setting value into a dependency return swappabletuplevalue split 10 first value the base class for all migrations migration files will import this from django db migrations migration and subclass it as a class called migration it will have one or more of the following attributes operations a list of operation instances probably from django db migrations operations dependencies a list of tuples of app_path migration_name run_before a list of tuples of app_path migration_name replaces a list of migration_names note that all migrations come out of migrations and into the loader or graph as instances having been initialized with their app label and name operations to apply during this migration in order other migrations that should be run before this migration should be a list of app migration_name other migrations that should be run after this one i e have this migration added to their dependencies useful to make third party apps migrations run after your auth_user replacement for example migration names in this app that this migration replaces if this is non empty this migration will only be applied if all these migrations are not applied is this an initial migration initial migrations are skipped on fake initial if the table or fields already exist if none check if the migration has any dependencies to determine if there are dependencies to tell if db introspection needs to be done if true always perform introspection if false never perform introspection whether to wrap the whole migration in a transaction only has an effect on database backends which support transactional ddl copy dependencies other attrs as we might mutate them at runtime take a projectstate and return a new one with the migration s operations applied to it preserve the original object state by default and return a mutated state from a copy take a project_state representing all migrations prior to this one and a schema_editor for a live database and apply the migration in a forwards order return the resulting project state for efficient reuse by following migrations if this operation cannot be represented as sql place a comment there instead save the state before the operation has run run the operation force a transaction on a non transactional ddl backend or an atomic operation inside a non atomic migration normal behaviour take a project_state representing all migrations prior to this one and a schema_editor for a live database and apply the migration in a reverse order the backwards migration process consists of two phases 1 the intermediate states from right before the first until right after the last operation inside this migration are preserved 2 the operations are applied in reverse order using the states recorded in step 1 construct all the intermediate states we need for a reverse migration phase 1 if it s irreversible error out preserve new state from previous run to not tamper the same state over all operations phase 2 force a transaction on a non transactional ddl backend or an atomic operation inside a non atomic migration normal behaviour suggest a name for the operations this migration might represent names are not guaranteed to be unique but put some effort into the fallback name to avoid vcs conflicts if possible subclass of tuple so django can tell this was originally a swappable dependency when it reads the migration file turn a setting value into a dependency
import re

from django.db.migrations.utils import get_migration_name_timestamp
from django.db.transaction import atomic

from .exceptions import IrreversibleError


class Migration:
    

    
    operations = []

    
    
    dependencies = []

    
    
    
    run_before = []

    
    
    
    replaces = []

    
    
    
    
    
    initial = None

    
    
    atomic = True

    def __init__(self, name, app_label):
        self.name = name
        self.app_label = app_label
        
        self.operations = list(self.__class__.operations)
        self.dependencies = list(self.__class__.dependencies)
        self.run_before = list(self.__class__.run_before)
        self.replaces = list(self.__class__.replaces)

    def __eq__(self, other):
        return (
            isinstance(other, Migration)
            and self.name == other.name
            and self.app_label == other.app_label
        )

    def __repr__(self):
        return "<Migration %s.%s>" % (self.app_label, self.name)

    def __str__(self):
        return "%s.%s" % (self.app_label, self.name)

    def __hash__(self):
        return hash("%s.%s" % (self.app_label, self.name))

    def mutate_state(self, project_state, preserve=True):
        
        new_state = project_state
        if preserve:
            new_state = project_state.clone()

        for operation in self.operations:
            operation.state_forwards(self.app_label, new_state)
        return new_state

    def apply(self, project_state, schema_editor, collect_sql=False):
        
        for operation in self.operations:
            
            
            if collect_sql:
                schema_editor.collected_sql.append("--")
                schema_editor.collected_sql.append("-- %s" % operation.describe())
                schema_editor.collected_sql.append("--")
                if not operation.reduces_to_sql:
                    schema_editor.collected_sql.append(
                        "-- THIS OPERATION CANNOT BE WRITTEN AS SQL"
                    )
                    continue
                collected_sql_before = len(schema_editor.collected_sql)
            
            old_state = project_state.clone()
            operation.state_forwards(self.app_label, project_state)
            
            atomic_operation = operation.atomic or (
                self.atomic and operation.atomic is not False
            )
            if not schema_editor.atomic_migration and atomic_operation:
                
                
                with atomic(schema_editor.connection.alias):
                    operation.database_forwards(
                        self.app_label, schema_editor, old_state, project_state
                    )
            else:
                
                operation.database_forwards(
                    self.app_label, schema_editor, old_state, project_state
                )
            if collect_sql and collected_sql_before == len(schema_editor.collected_sql):
                schema_editor.collected_sql.append("-- (no-op)")
        return project_state

    def unapply(self, project_state, schema_editor, collect_sql=False):
        
        
        to_run = []
        new_state = project_state
        
        for operation in self.operations:
            
            if not operation.reversible:
                raise IrreversibleError(
                    "Operation %s in %s is not reversible" % (operation, self)
                )
            
            
            new_state = new_state.clone()
            old_state = new_state.clone()
            operation.state_forwards(self.app_label, new_state)
            to_run.insert(0, (operation, old_state, new_state))

        
        for operation, to_state, from_state in to_run:
            if collect_sql:
                schema_editor.collected_sql.append("--")
                schema_editor.collected_sql.append("-- %s" % operation.describe())
                schema_editor.collected_sql.append("--")
                if not operation.reduces_to_sql:
                    schema_editor.collected_sql.append(
                        "-- THIS OPERATION CANNOT BE WRITTEN AS SQL"
                    )
                    continue
                collected_sql_before = len(schema_editor.collected_sql)
            atomic_operation = operation.atomic or (
                self.atomic and operation.atomic is not False
            )
            if not schema_editor.atomic_migration and atomic_operation:
                
                
                with atomic(schema_editor.connection.alias):
                    operation.database_backwards(
                        self.app_label, schema_editor, from_state, to_state
                    )
            else:
                
                operation.database_backwards(
                    self.app_label, schema_editor, from_state, to_state
                )
            if collect_sql and collected_sql_before == len(schema_editor.collected_sql):
                schema_editor.collected_sql.append("-- (no-op)")
        return project_state

    def suggest_name(self):
        
        if self.initial:
            return "initial"

        raw_fragments = [op.migration_name_fragment for op in self.operations]
        fragments = [re.sub(r"\W+", "_", name) for name in raw_fragments if name]

        if not fragments or len(fragments) != len(self.operations):
            return "auto_%s" % get_migration_name_timestamp()

        name = fragments[0]
        for fragment in fragments[1:]:
            new_name = f"{name}_{fragment}"
            if len(new_name) > 52:
                name = f"{name}_and_more"
                break
            name = new_name
        return name


class SwappableTuple(tuple):
    

    def __new__(cls, value, setting):
        self = tuple.__new__(cls, value)
        self.setting = setting
        return self


def swappable_dependency(value):
    
    return SwappableTuple((value.split(".", 1)[0], "__first__"), value)