def test_migrations_not_applied_on_deferred_sql_failure(self): """Migrations are not recorded if deferred SQL application fails.""" class DeferredSQL: def __str__(self): raise DatabaseError('Failed to apply deferred SQL') class Migration(migrations.Migration): atomic = False def apply(self, project_state, schema_editor, collect_sql=False): schema_editor.deferred_sql.append(DeferredSQL()) executor = MigrationExecutor(connection) with self.assertRaisesMessage(DatabaseError, 'Failed to apply deferred SQL'): executor.apply_migration( ProjectState(), Migration('0001_initial', 'deferred_sql'), ) # The migration isn't recorded as applied since it failed. migration_recorder = MigrationRecorder(connection) self.assertIs( migration_recorder.migration_qs.filter( app='deferred_sql', name='0001_initial', ).exists(), False, )
def execute_migration(schema_editor, operations, project=None): """Executes the specified migration operations using the specified schema editor. Arguments: schema_editor: The schema editor to use to execute the migrations. operations: The migration operations to execute. project: The project state to use during the migrations. """ project = project or migrations.state.ProjectState.from_apps(apps) class Migration(migrations.Migration): pass Migration.operations = operations executor = MigrationExecutor(schema_editor.connection) executor.apply_migration(project, Migration('eh', 'postgres_extra'))
def apply_migration(operations, state=None, backwards: bool = False): """Executes the specified migration operations using the specified schema editor. Arguments: operations: The migration operations to execute. state: The state state to use during the migrations. backwards: Whether to apply the operations in reverse (backwards). """ state = state or migrations.state.ProjectState.from_apps(apps) class Migration(migrations.Migration): pass Migration.operations = operations migration = Migration("migration", "tests") executor = MigrationExecutor(connection) if not backwards: executor.apply_migration(state, migration) else: executor.unapply_migration(state, migration) return migration
def test_migrations_applied_and_recorded_atomically(self): """Migrations are applied and recorded atomically.""" class Migration(migrations.Migration): operations = [ migrations.CreateModel( "model", [ ("id", models.AutoField(primary_key=True)), ], ), ] executor = MigrationExecutor(connection) with mock.patch( "django.db.migrations.executor.MigrationExecutor.record_migration" ) as record_migration: record_migration.side_effect = RuntimeError( "Recording migration failed.") with self.assertRaisesMessage(RuntimeError, "Recording migration failed."): executor.apply_migration( ProjectState(), Migration("0001_initial", "record_migration"), ) executor.migrate([("migrations", "0001_initial")]) # The migration isn't recorded as applied since it failed. migration_recorder = MigrationRecorder(connection) self.assertIs( migration_recorder.migration_qs.filter( app="record_migration", name="0001_initial", ).exists(), False, ) self.assertTableNotExists("record_migration_model")
def test_migrations_applied_and_recorded_atomically(self): """Migrations are applied and recorded atomically.""" class Migration(migrations.Migration): operations = [ migrations.CreateModel('model', [ ('id', models.AutoField(primary_key=True)), ]), ] executor = MigrationExecutor(connection) with mock.patch( 'django.db.migrations.executor.MigrationExecutor.record_migration' ) as record_migration: record_migration.side_effect = RuntimeError( 'Recording migration failed.') with self.assertRaisesMessage(RuntimeError, 'Recording migration failed.'): executor.apply_migration( ProjectState(), Migration('0001_initial', 'record_migration'), ) executor.migrate([('migrations', '0001_initial')]) # The migration isn't recorded as applied since it failed. migration_recorder = MigrationRecorder(connection) self.assertIs( migration_recorder.migration_qs.filter( app='record_migration', name='0001_initial', ).exists(), False, ) self.assertTableNotExists('record_migration_model')
def on_pre_migrate(connection, **kwargs): """ Ensures that custom user migration executed before main migration process. The main problem with existing application custom user implementation is failing migration consistency check. But in fact migration is ok, the problem is that migration plan expects user migration applied before others. So only thing we need to do, is to force custom user migration. Here is approach when we detect such situation during migration process and manually applying custom user migration before checks executed. 1. This method detects: 1.1. if it executed within migrate command 1.2. if other miggrations already applied 1.3. custom_user migrations not applied 2. Manually applies custom_user migration. """ if len(argv) < 2 or argv[1] != 'migrate': return executor = MigrationExecutor(connection, get_migration_callback()) executor.loader.load_disk() is_fresh = not executor.loader.applied_migrations is_applied = CUSTOM_USER_MIGRATION in executor.loader.applied_migrations if is_fresh or is_applied: return migration = executor.loader.disk_migrations[CUSTOM_USER_MIGRATION] state = executor._create_project_state( with_applied_migrations=True) # noqa protected-access executor.apply_migration(state, migration)
def get_fake_model(): """Creates a fake model to use during unit tests.""" global MODEL if MODEL: return MODEL class TestModel(LocalizedModel): """Model used for testing the :see:LocalizedAutoSlugField.""" app_label = 'localized_fields' title = LocalizedField() slug = LocalizedAutoSlugField(populate_from='title') class TestProject: def clone(self, *args, **kwargs): return self class TestMigration(migrations.Migration): operations = [HStoreExtension()] with connection.schema_editor() as schema_editor: migration_executor = MigrationExecutor(schema_editor.connection) migration_executor.apply_migration( TestProject(), TestMigration('eh', 'localized_fields')) schema_editor.create_model(TestModel) MODEL = TestModel return MODEL
def get_fake_model(fields=None, model_base=LocalizedModel, meta_options={}): """Creates a fake model to use during unit tests.""" model = define_fake_model(fields, model_base, meta_options) class TestProject: def clone(self, *_args, **_kwargs): return self @property def apps(self): return self class TestMigration(migrations.Migration): operations = [HStoreExtension()] with connection.schema_editor() as schema_editor: migration_executor = MigrationExecutor(schema_editor.connection) migration_executor.apply_migration( TestProject(), TestMigration('eh', 'postgres_extra')) schema_editor.create_model(model) return model
def migrate(self): """Executes the recorded migrations.""" while len(self.migrations) > 0: migration = self.migrations.pop() with connection.schema_editor() as schema_editor: migration_executor = MigrationExecutor( schema_editor.connection) migration_executor.apply_migration(self.project_state, migration)
def apply_django_migration(migration_cls, migration_name='9999', app_label='testapp', executor=None): if executor is None: executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS]) migration = migration_cls(migration_name, app_label) key = (migration.app_label, migration.name) executor.loader.graph.add_node(key, migration) for parent in migration.dependencies: executor.loader.graph.add_dependency(migration, key, parent) try: executor.apply_migration(migration) except TypeError: state = executor.loader.project_state(parent) executor.apply_migration(state, migration) return executor
def get_fake_model(fields={}, model_base=models.Model, options={}): """Create fake model to use during unit tests.""" model = define_fake_model(fields, model_base, options) class TestProject: def clone(self, *_args, **_kwargs): return self class TestMigration(migrations.Migration): operations = [HStoreExtension()] with connection.schema_editor() as schema_editor: migration_executor = MigrationExecutor(schema_editor.connection) migration_executor.apply_migration( TestProject(), TestMigration("caluma_extra", "core")) schema_editor.create_model(model) return model
def migrate(self, *filters: List[str]): """ Executes the recorded migrations. Arguments: filters: List of strings to filter SQL statements on. Returns: The filtered calls of every migration """ calls_for_migrations = [] while len(self.migrations) > 0: migration = self.migrations.pop() with filtered_schema_editor(*filters) as (schema_editor, calls): migration_executor = MigrationExecutor(schema_editor.connection) migration_executor.apply_migration( self.project_state, migration ) calls_for_migrations.append(calls) return calls_for_migrations
def get_fake_model(name='TestModel', fields=None): """Creates a fake model to use during unit tests.""" model = define_fake_model(name, fields) class TestProject: def clone(self, *_args, **_kwargs): return self @property def apps(self): return self class TestMigration(migrations.Migration): operations = [HStoreExtension()] with connection.schema_editor() as schema_editor: migration_executor = MigrationExecutor(schema_editor.connection) migration_executor.apply_migration( TestProject(), TestMigration('eh', 'localized_fields')) schema_editor.create_model(model) return model