예제 #1
0
    def test_apply_migrations(self):
        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")

        # We should start with no migrations
        self.assertEqual(list(MigrationHistory.objects.all()), [])

        # Apply them normally
        migrate_app(migrations,
                    target_name=None,
                    fake=False,
                    load_initial_data=True)

        # We should finish with all migrations
        self.assertListEqual(
            (
                (u"fakeapp", u"0001_spam"),
                (u"fakeapp", u"0002_eggs"),
                (u"fakeapp", u"0003_alter_spam"),
            ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Now roll them backwards
        migrate_app(migrations, target_name="zero", fake=False)

        # Finish with none
        self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #2
0
파일: logic.py 프로젝트: hsmett/medianav
 def test_apply_migrations(self):
     migration.MigrationHistory.objects.all().delete()
     app = migration.get_app("fakeapp")
     
     # We should start with no migrations
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
     
     # Apply them normally
     tree = migration.dependency_tree()
     migration.migrate_app(app, tree, target_name=None, resolve_mode=None, fake=False, verbosity=0)
     
     # We should finish with all migrations
     self.assertListEqual(
         (
             (u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),
             (u"fakeapp", u"0003_alter_spam"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Now roll them backwards
     migration.migrate_app(app, tree, target_name="zero", resolve_mode=None, fake=False, verbosity=0)
     
     # Finish with none
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
예제 #3
0
    def test_migration_merge_forwards(self):
        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")

        # We should start with no migrations
        self.assertEqual(list(MigrationHistory.objects.all()), [])

        # Insert one in the wrong order
        MigrationHistory.objects.create(app_name="fakeapp",
                                        migration="0002_eggs",
                                        applied=datetime.datetime.now())

        # Did it go in?
        self.assertListEqual(
            ((u"fakeapp", u"0002_eggs"), ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Apply them normally
        self.assertRaises(exceptions.InconsistentMigrationHistory,
                          migrate_app,
                          migrations,
                          target_name=None,
                          fake=False)
        self.assertRaises(exceptions.InconsistentMigrationHistory,
                          migrate_app,
                          migrations,
                          target_name='zero',
                          fake=False)
        try:
            migrate_app(migrations, target_name=None, fake=False)
        except exceptions.InconsistentMigrationHistory, e:
            self.assertEqual(
                [(migrations['0002_eggs'], [migrations['0001_spam']])],
                e.problems)
예제 #4
0
파일: logic.py 프로젝트: hsmett/medianav
 def test_migration_merge_forwards(self):
     migration.MigrationHistory.objects.all().delete()
     app = migration.get_app("fakeapp")
     
     # We should start with no migrations
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
     
     # Insert one in the wrong order
     migration.MigrationHistory.objects.create(
         app_name = "fakeapp",
         migration = "0002_eggs",
         applied = datetime.datetime.now(),
     )
     
     # Did it go in?
     self.assertListEqual(
         (
             (u"fakeapp", u"0002_eggs"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply them normally
     tree = migration.dependency_tree()
     try:
         # Redirect the error it will print to nowhere
         stdout, sys.stdout = sys.stdout, StringIO.StringIO()
         migration.migrate_app(app, tree, target_name=None, resolve_mode=None, fake=False, verbosity=0)
         sys.stdout = stdout
     except SystemExit:
         pass
     
     # Nothing should have changed (no merge mode!)
     self.assertListEqual(
         (
             (u"fakeapp", u"0002_eggs"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply with merge
     migration.migrate_app(app, tree, target_name=None, resolve_mode="merge", fake=False, verbosity=0)
     
     # We should finish with all migrations
     self.assertListEqual(
         (
             (u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),
             (u"fakeapp", u"0003_alter_spam"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Now roll them backwards
     migration.migrate_app(app, tree, target_name="0002", resolve_mode=None, fake=False, verbosity=0)
     migration.migrate_app(app, tree, target_name="0001", resolve_mode=None, fake=True, verbosity=0)
     migration.migrate_app(app, tree, target_name="zero", resolve_mode=None, fake=False, verbosity=0)
     
     # Finish with none
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
예제 #5
0
파일: logic.py 프로젝트: notanumber/south
    def test_migration_merge_forwards(self):
        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")

        # We should start with no migrations
        self.assertEqual(list(MigrationHistory.objects.all()), [])

        # Insert one in the wrong order
        MigrationHistory.objects.create(app_name="fakeapp", migration="0002_eggs", applied=datetime.datetime.now())

        # Did it go in?
        self.assertListEqual(
            ((u"fakeapp", u"0002_eggs"),), MigrationHistory.objects.values_list("app_name", "migration")
        )

        # Apply them normally
        self.assertRaises(
            exceptions.InconsistentMigrationHistory, migrate_app, migrations, target_name=None, fake=False
        )
        self.assertRaises(
            exceptions.InconsistentMigrationHistory, migrate_app, migrations, target_name="zero", fake=False
        )
        try:
            migrate_app(migrations, target_name=None, fake=False)
        except exceptions.InconsistentMigrationHistory, e:
            self.assertEqual([(migrations["0002_eggs"], [migrations["0001_spam"]])], e.problems)
예제 #6
0
 def test_migration_merge_forwards(self):
     
     app = migration.get_app("fakeapp")
     
     # We should start with no migrations
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
     
     # Insert one in the wrong order
     migration.MigrationHistory.objects.create(
         app_name = "fakeapp",
         migration = "0002_eggs",
         applied = datetime.datetime.now(),
     )
     
     # Did it go in?
     self.assertListEqual(
         (
             (u"fakeapp", u"0002_eggs"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply them normally
     try:
         migration.migrate_app(app, target_name=None, resolve_mode=None, fake=False, silent=True)
     except SystemExit:
         pass
     
     # Nothing should have changed (no merge mode!)
     self.assertListEqual(
         (
             (u"fakeapp", u"0002_eggs"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply with merge
     migration.migrate_app(app, target_name=None, resolve_mode="merge", fake=False, silent=True)
     
     # We should finish with all migrations
     self.assertListEqual(
         (
             (u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),
             (u"fakeapp", u"0003_alter_spam"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Now roll them backwards
     migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
     migration.migrate_app(app, target_name="0001", resolve_mode=None, fake=True, silent=True)
     migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
     
     # Finish with none
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
예제 #7
0
파일: logic.py 프로젝트: artemrizhov/itcm
 def test_migration_merge_forwards(self):
     
     app = migration.get_app("fakeapp")
     
     # We should start with no migrations
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
     
     # Insert one in the wrong order
     migration.MigrationHistory.objects.create(
         app_name = "fakeapp",
         migration = "0002_eggs",
         applied = datetime.datetime.now(),
     )
     
     # Did it go in?
     self.assertListEqual(
         (
             (u"fakeapp", u"0002_eggs"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply them normally
     try:
         migration.migrate_app(app, target_name=None, resolve_mode=None, fake=False, silent=True)
     except SystemExit:
         pass
     
     # Nothing should have changed (no merge mode!)
     self.assertListEqual(
         (
             (u"fakeapp", u"0002_eggs"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply with merge
     migration.migrate_app(app, target_name=None, resolve_mode="merge", fake=False, silent=True)
     
     # We should finish with all migrations
     self.assertListEqual(
         (
             (u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),
             (u"fakeapp", u"0003_alter_spam"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Now roll them backwards
     migration.migrate_app(app, target_name="0002", resolve_mode=None, fake=False, silent=True)
     migration.migrate_app(app, target_name="0001", resolve_mode=None, fake=True, silent=True)
     migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
     
     # Finish with none
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
예제 #8
0
파일: logic.py 프로젝트: hsmett/medianav
    def test_alter_column_null(self):
        def null_ok():
            from django.db import connection, transaction
            # the DBAPI introspection module fails on postgres NULLs.
            cursor = connection.cursor()
            try:
                cursor.execute("INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, 10.1, now(), NULL);")
            except:
                transaction.rollback()
                return False
            else:
                cursor.execute("DELETE FROM southtest_spam")
                transaction.commit()
                return True
        
        app = migration.get_app("fakeapp")
        tree = migration.dependency_tree()
        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
        
        # by default name is NOT NULL
        migration.migrate_app(app, tree, target_name="0002", resolve_mode=None, fake=False, verbosity=0)
        self.failIf(null_ok())
        
        # after 0003, it should be NULL
        migration.migrate_app(app, tree, target_name="0003", resolve_mode=None, fake=False, verbosity=0)
        self.assert_(null_ok())

        # make sure it is NOT NULL again
        migration.migrate_app(app, tree, target_name="0002", resolve_mode=None, fake=False, verbosity=0)
        self.failIf(null_ok(), 'name not null after migration')
        
        # finish with no migrations, otherwise other tests fail...
        migration.migrate_app(app, tree, target_name="zero", resolve_mode=None, fake=False, verbosity=0)
        self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
예제 #9
0
    def handle(self, *args, **options):
        verbosity = int(options.get('verbosity', '1'))
        assert django.VERSION < (1, 7)
        from south import migration
        from south.models import MigrationHistory

        try:
            MigrationHistory.objects.count()
        except OperationalError:
            return

        apps  = list(migration.all_migrations())
        applied_migrations = MigrationHistory.objects.filter(app_name__in=[app.app_label() for app in apps])
        applied_migrations = ['%s.%s' % (mi.app_name, mi.migration) for mi in applied_migrations]

        for app in apps:
            for app_migration in app:
                migration_name = '%s.%s' % (app_migration.app_label(), app_migration.name())
                
                print migration_name, bool(migration_name in applied_migrations)
                if migration_name not in applied_migrations:
                    result = migration.migrate_app(
                        app,
                        app_migration.name(),
                        verbosity = verbosity,
                        db_dry_run = True,
                    )
                    if result is False:
                        sys.exit('Migration %s failed.' % migration_name)
예제 #10
0
파일: logic.py 프로젝트: amyth/django-south
    def test_alter_column_null(self):
        
        def null_ok():
            from django.db import connection, transaction
            # the DBAPI introspection module fails on postgres NULLs.
            cursor = connection.cursor()
        
            # SQLite has weird now()
            if db.backend_name == "sqlite3":
                now_func = "DATETIME('NOW')"
            else:
                now_func = "NOW()"
            
            try:
                cursor.execute("INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, 10.1, %s, NULL);" % now_func)
            except:
                transaction.rollback()
                return False
            else:
                cursor.execute("DELETE FROM southtest_spam")
                transaction.commit()
                return True

        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")
        
        # by default name is NOT NULL
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok())
        self.assertListEqual(
            ((u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )
        
        # after 0003, it should be NULL
        migrate_app(migrations, target_name="0003", fake=False)
        self.assert_(null_ok())
        self.assertListEqual(
            ((u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),
             (u"fakeapp", u"0003_alter_spam"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # make sure it is NOT NULL again
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok(), 'name not null after migration')
        self.assertListEqual(
            ((u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )
        
        # finish with no migrations, otherwise other tests fail...
        migrate_app(migrations, target_name="zero", fake=False)
        self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #11
0
    def test_alter_column_null(self):
        
        def null_ok():
            from django.db import connection, transaction
            # the DBAPI introspection module fails on postgres NULLs.
            cursor = connection.cursor()
        
            # SQLite has weird now()
            if db.backend_name == "sqlite3":
                now_func = "DATETIME('NOW')"
            else:
                now_func = "NOW()"
            
            try:
                cursor.execute("INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, 10.1, %s, NULL);" % now_func)
            except:
                transaction.rollback()
                return False
            else:
                cursor.execute("DELETE FROM southtest_spam")
                transaction.commit()
                return True

        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")
        
        # by default name is NOT NULL
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok())
        self.assertListEqual(
            ((u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )
        
        # after 0003, it should be NULL
        migrate_app(migrations, target_name="0003", fake=False)
        self.assert_(null_ok())
        self.assertListEqual(
            ((u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),
             (u"fakeapp", u"0003_alter_spam"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # make sure it is NOT NULL again
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok(), 'name not null after migration')
        self.assertListEqual(
            ((u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )
        
        # finish with no migrations, otherwise other tests fail...
        migrate_app(migrations, target_name="zero", fake=False)
        self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #12
0
    def handle(self, app=None, target=None, skip=False, merge=False, backwards=False, fake=False, db_dry_run=False,
               show_list=False, show_changes=False, database=DEFAULT_DB_ALIAS, delete_ghosts=False, ignore_ghosts=False, **options):

        # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb
        # This code imports any module named 'management' in INSTALLED_APPS.
        # The 'management' module is the preferred way of listening to post_syncdb
        # signals, and since we're sending those out with create_table migrations,
        # we need apps to behave correctly.
        for app_name in settings.INSTALLED_APPS:
            try:
                import_module('.management', app_name)
            except ImportError as exc:
                msg = exc.args[0]
                if not msg.startswith('No module named') or 'management' not in msg:
                    raise
        # END DJANGO DUPE CODE

        # if all_apps flag is set, shift app over to target
        if options.get('all_apps', False):
            target = app
            app = None

        # Migrate each app
        if app:
            try:
                apps = [Migrations(app)]
            except NoMigrations:
                print("The app '%s' does not appear to use migrations." % app)
                print("./manage.py migrate " + self.args)
                return
        else:
            apps = list(migration.all_migrations())

        # Do we need to show the list of migrations?
        if show_list and apps:
            list_migrations(apps, database, **options)

        if show_changes and apps:
            show_migration_changes(apps)

        if not (show_list or show_changes):

            for app in apps:
                result = migration.migrate_app(
                    app,
                    target_name=target,
                    fake=fake,
                    db_dry_run=db_dry_run,
                    verbosity=int(options.get('verbosity', 0)),
                    interactive=options.get('interactive', True),
                    load_initial_data=not options.get('no_initial_data', False),
                    merge=merge,
                    skip=skip,
                    database=database,
                    delete_ghosts=delete_ghosts,
                    ignore_ghosts=ignore_ghosts,
                )
                if result is False:
                    sys.exit(1)  # Migration failed, so the command fails.
예제 #13
0
파일: logic.py 프로젝트: notanumber/south
    def test_apply_migrations(self):
        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")

        # We should start with no migrations
        self.assertEqual(list(MigrationHistory.objects.all()), [])

        # Apply them normally
        migrate_app(migrations, target_name=None, fake=False, load_initial_data=True)

        # We should finish with all migrations
        self.assertListEqual(
            ((u"fakeapp", u"0001_spam"), (u"fakeapp", u"0002_eggs"), (u"fakeapp", u"0003_alter_spam")),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Now roll them backwards
        migrate_app(migrations, target_name="zero", fake=False)

        # Finish with none
        self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #14
0
 def test_apply_migrations(self):
     
     app = migration.get_app("fakeapp")
     
     # We should start with no migrations
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
     
     # Apply them normally
     migration.migrate_app(app, target_name=None, resolve_mode=None, fake=False, silent=True)
     
     # We should finish with all migrations
     self.assertListEqual(
         (
             (u"fakeapp", u"0001_spam"),
             (u"fakeapp", u"0002_eggs"),
         ),
         migration.MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Now roll them backwards
     migration.migrate_app(app, target_name="zero", resolve_mode=None, fake=False, silent=True)
     
     # Finish with none
     self.assertEqual(list(migration.MigrationHistory.objects.all()), [])
예제 #15
0
파일: sfd.py 프로젝트: Fantomas42/nose-sfd
    def begin(self):
        """
        Initialize the test environment then create the test database
        and switch the connection over to that database.
        """
        import django
        from django.conf import settings
        from django.db import connection
        from django.core import management
        from django.test.utils import setup_test_environment

        use_south = 'south' in settings.INSTALLED_APPS
        if use_south:
            from south import migration
            from south.hacks import hacks

        try:
            self.original_db_name = settings.DATABASE_NAME
        except AttributeError:  # Django > 1.2
            self.original_db_name = settings.DATABASES['default']['NAME']

        try:
            django.setup()  # Django >= 1.7
        except AttributeError:
            pass
        setup_test_environment()

        if use_south:
            management.get_commands()
            hacks.patch_flush_during_test_db_creation()

        connection.creation.create_test_db(self.verbosity)

        if use_south:
            for app in migration.all_migrations():
                migration.migrate_app(app, verbosity=self.verbosity)
예제 #16
0
class Command(BaseCommand):
    option_list = BaseCommand.option_list + (
        make_option('--all',
                    action='store_true',
                    dest='all_apps',
                    default=False,
                    help='Run the specified migration for all apps.'),
        make_option(
            '--list',
            action='store_true',
            dest='show_list',
            default=False,
            help='List migrations noting those that have been applied'),
        make_option('--changes',
                    action='store_true',
                    dest='show_changes',
                    default=False,
                    help='List changes for migrations'),
        make_option('--skip',
                    action='store_true',
                    dest='skip',
                    default=False,
                    help='Will skip over out-of-order missing migrations'),
        make_option(
            '--merge',
            action='store_true',
            dest='merge',
            default=False,
            help=
            'Will run out-of-order missing migrations as they are - no rollbacks.'
        ),
        make_option('--no-initial-data',
                    action='store_true',
                    dest='no_initial_data',
                    default=False,
                    help='Skips loading initial data if specified.'),
        make_option(
            '--fake',
            action='store_true',
            dest='fake',
            default=False,
            help=
            "Pretends to do the migrations, but doesn't actually execute them."
        ),
        make_option(
            '--db-dry-run',
            action='store_true',
            dest='db_dry_run',
            default=False,
            help=
            "Doesn't execute the SQL generated by the db methods, and doesn't store a record that the migration(s) occurred. Useful to test migrations before applying them."
        ),
        make_option(
            '--delete-ghost-migrations',
            action='store_true',
            dest='delete_ghosts',
            default=False,
            help=
            "Tells South to delete any 'ghost' migrations (ones in the database but not on disk)."
        ),
        make_option(
            '--ignore-ghost-migrations',
            action='store_true',
            dest='ignore_ghosts',
            default=False,
            help=
            "Tells South to ignore any 'ghost' migrations (ones in the database but not on disk) and continue to apply new migrations."
        ),
        make_option(
            '--noinput',
            action='store_false',
            dest='interactive',
            default=True,
            help='Tells Django to NOT prompt the user for input of any kind.'),
        make_option('--database',
                    action='store',
                    dest='database',
                    default=DEFAULT_DB_ALIAS,
                    help='Nominates a database to synchronize. '
                    'Defaults to the "default" database.'),
        make_option(
            '--hack',  # KA-LITE-MOD: needed for relaunch_external hack
            action="store_true",
            dest="hack",
            default=False,
            help="Flag that we're getting an external callback ",
        ),
    )
    if '--verbosity' not in [
            opt.get_opt_string() for opt in BaseCommand.option_list
    ]:
        option_list += (make_option(
            '--verbosity',
            action='store',
            dest='verbosity',
            default='1',
            type='choice',
            choices=['0', '1', '2'],
            help=
            'Verbosity level; 0=minimal output, 1=normal output, 2=all output'
        ), )
    help = "Runs migrations for all apps."
    args = "[appname] [migrationname|zero] [--all] [--list] [--skip] [--merge] [--no-initial-data] [--fake] [--db-dry-run] [--database=dbalias]"

    def relaunch_external(self):
        """
        This is a KA Lite hack. #KA-LITE-MOD

        In our git-based update command (until version 0.10.3), we update the code, then run
        run the 'migrate' command under the old code (since it's loaded into memory).
        This can cause conflicting / now-outdated imports.

        The right thing to do is to run migrate via subprocess, so that it runs all fresh, new code.
        Alas, we've shipped versions that don't do this already, so we can't go back and fix.

        The hack here is: detect when this is happening, then force migrate to re-launch itself via subprocess.

        Note that this only works if this file (migrate.py) hasn't already been loaded into the process.  It
        shouldn't be... but it's worth keeping in mind!
        """
        import sys
        import settings
        import utils.django_utils.command
        reload(
            utils.django_utils.command
        )  # this is necessary because the 0.10.2 version of this code has a bug!

        # Launch through subprocess, then print output.
        sys.stdout.write(
            "[NOTE version upgrade hack: running 'migrate' through subprocess.]\n\n"
        )
        sys.stdout.write(
            "Please wait. DO NOT CANCEL WHILE MIGRATE RUNS, EVEN THOUGH YOU'RE RECEIVING NO OUTPUT!!  JUST WAIT!!\n"
        )
        sys.stdout.write(
            "Output will print below when migrate is complete.\n\n")

        (out, err,
         rc) = utils.django_utils.command.call_outside_command_with_output(
             "migrate",
             merge=True,
             hack=True,
             manage_py_dir=settings.PROJECT_PATH)
        sys.stdout.write(out)
        if rc:
            sys.stderr.write(err)
        sys.exit(0)  # abort the rest of the migrate / update command

    def handle(self,
               app=None,
               target=None,
               skip=False,
               merge=False,
               backwards=False,
               fake=False,
               db_dry_run=False,
               show_list=False,
               show_changes=False,
               database=DEFAULT_DB_ALIAS,
               delete_ghosts=False,
               ignore_ghosts=False,
               **options):

        if "update" in sys.argv and "--hack" not in sys.argv:
            self.relaunch_external()

        # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb
        # This code imports any module named 'management' in INSTALLED_APPS.
        # The 'management' module is the preferred way of listening to post_syncdb
        # signals, and since we're sending those out with create_table migrations,
        # we need apps to behave correctly.
        for app_name in settings.INSTALLED_APPS:
            try:
                import_module('.management', app_name)
            except ImportError, exc:
                msg = exc.args[0]
                if not msg.startswith(
                        'No module named') or 'management' not in msg:
                    raise
        # END DJANGO DUPE CODE

        # if all_apps flag is set, shift app over to target
        if options.get('all_apps', False):
            target = app
            app = None

        # Migrate each app
        if app:
            try:
                apps = [Migrations(app)]
            except NoMigrations:
                print "The app '%s' does not appear to use migrations." % app
                print "./manage.py migrate " + self.args
                return
        else:
            apps = list(migration.all_migrations())

        # Do we need to show the list of migrations?
        if show_list and apps:
            list_migrations(apps, database, **options)

        if show_changes and apps:
            show_migration_changes(apps)

        if not (show_list or show_changes):

            for app in apps:
                result = migration.migrate_app(
                    app,
                    target_name=target,
                    fake=fake,
                    db_dry_run=db_dry_run,
                    verbosity=int(options.get('verbosity', 0)),
                    interactive=options.get('interactive', True),
                    load_initial_data=not options.get('no_initial_data',
                                                      False),
                    merge=merge,
                    skip=skip,
                    database=database,
                    delete_ghosts=delete_ghosts,
                    ignore_ghosts=ignore_ghosts,
                )
                if result is False:
                    sys.exit(1)  # Migration failed, so the command fails.
예제 #17
0
 def test_migration_merge_forwards(self):
     migrations = Migrations("fakeapp")
     
     # We should start with no migrations
     self.assertEqual(list(MigrationHistory.objects.all()), [])
     
     # Insert one in the wrong order
     MigrationHistory.objects.create(app_name = "fakeapp",
                                     migration = "0002_eggs",
                                     applied = datetime.datetime.now())
     
     # Did it go in?
     self.assertListEqual(
         (("fakeapp", "0002_eggs"),),
         MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply them normally
     self.assertRaises(exceptions.InconsistentMigrationHistory,
                       migrate_app,
                       migrations, target_name=None, fake=False)
     self.assertRaises(exceptions.InconsistentMigrationHistory,
                       migrate_app,
                       migrations, target_name='zero', fake=False)
     try:
         migrate_app(migrations, target_name=None, fake=False)
     except exceptions.InconsistentMigrationHistory as e:
         self.assertEqual(
             [
                 (
                     migrations['0002_eggs'],
                     migrations['0001_spam'],
                 )
             ],
             e.problems,
         )
     try:
         migrate_app(migrations, target_name="zero", fake=False)
     except exceptions.InconsistentMigrationHistory as e:
         self.assertEqual(
             [
                 (
                     migrations['0002_eggs'],
                     migrations['0001_spam'],
                 )
             ],
             e.problems,
         )
     
     # Nothing should have changed (no merge mode!)
     self.assertListEqual(
         (("fakeapp", "0002_eggs"),),
         MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Apply with merge
     migrate_app(migrations, target_name=None, merge=True, fake=False)
     
     # We should finish with all migrations
     self.assertListEqual(
         (("fakeapp", "0001_spam"),
          ("fakeapp", "0002_eggs"),
          ("fakeapp", "0003_alter_spam"),),
         MigrationHistory.objects.values_list("app_name", "migration"),
     )
     
     # Now roll them backwards
     migrate_app(migrations, target_name="0002", fake=False)
     migrate_app(migrations, target_name="0001", fake=True)
     migrate_app(migrations, target_name="zero", fake=False)
     
     # Finish with none
     self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #18
0
class Command(BaseCommand):
    option_list = BaseCommand.option_list + (
        make_option('--all', action='store_true', dest='all_apps', default=False,
            help='Run the specified migration for all apps.'),
        make_option('--list', action='store_true', dest='list', default=False,
            help='List migrations noting those that have been applied'),
        make_option('--skip', action='store_true', dest='skip', default=False,
            help='Will skip over out-of-order missing migrations'),
        make_option('--merge', action='store_true', dest='merge', default=False,
            help='Will run out-of-order missing migrations as they are - no rollbacks.'),
        make_option('--no-initial-data', action='store_true', dest='no_initial_data', default=False,
            help='Skips loading initial data if specified.'),
        make_option('--fake', action='store_true', dest='fake', default=False,
            help="Pretends to do the migrations, but doesn't actually execute them."),
        make_option('--db-dry-run', action='store_true', dest='db_dry_run', default=False,
            help="Doesn't execute the SQL generated by the db methods, and doesn't store a record that the migration(s) occurred. Useful to test migrations before applying them."),
    )
    if '--verbosity' not in [opt.get_opt_string() for opt in BaseCommand.option_list]:
        option_list += (
            make_option('--verbosity', action='store', dest='verbosity', default='1',
            type='choice', choices=['0', '1', '2'],
            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
        )
    help = "Runs migrations for all apps."
    args = "[appname] [migrationname|zero] [--all] [--list] [--skip] [--merge] [--no-initial-data] [--fake] [--db-dry-run]"

    def handle(self, app=None, target=None, skip=False, merge=False, backwards=False, fake=False, db_dry_run=False, list=False, **options):

        # Work out what the resolve mode is
        resolve_mode = merge and "merge" or (skip and "skip" or None)
        
        # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb
        # This code imports any module named 'management' in INSTALLED_APPS.
        # The 'management' module is the preferred way of listening to post_syncdb
        # signals, and since we're sending those out with create_table migrations,
        # we need apps to behave correctly.
        for app_name in settings.INSTALLED_APPS:
            try:
                __import__(app_name + '.management', {}, {}, [''])
            except ImportError, exc:
                msg = exc.args[0]
                if not msg.startswith('No module named') or 'management' not in msg:
                    raise
        # END DJANGO DUPE CODE
        
        # if all_apps flag is set, shift app over to target
        if options.get('all_apps', False):
            target = app
            app = None

        # Migrate each app
        if app:
            apps = [migration.get_app(app.split(".")[-1])]
            if apps == [None]:
                print "The app '%s' does not appear to use migrations." % app
                print "./manage.py migrate " + self.args
                return
        else:
            apps = migration.get_migrated_apps()
        
        if list and apps:
            list_migrations(apps)
        
        if not list:
            tree = migration.dependency_tree()
            
            for app in apps:
                result = migration.migrate_app(
                    app,
                    tree,
                    resolve_mode = resolve_mode,
                    target_name = target,
                    fake = fake,
                    db_dry_run = db_dry_run,
                    verbosity = int(options.get('verbosity', 0)),
                    load_inital_data = not options.get('no_initial_data', False),
                    skip = skip,
                )
                if result is False:
                    return
예제 #19
0
    def handle(self, app=None, name="", added_model_list=None,
               added_field_list=None, freeze_list=None, initial=False,
               auto=False, stdout=False, added_index_list=None, verbosity=1,
               empty=False, update=False, **options):

        # Any supposed lists that are None become empty lists
        added_model_list = added_model_list or []
        added_field_list = added_field_list or []
        added_index_list = added_index_list or []
        freeze_list = freeze_list or []

        # --stdout means name = -
        if stdout:
            name = "-"

        # Only allow valid names
        if re.search('[^_\w]', name) and name != "-":
            self.error(
                "Migration names should contain only alphanumeric characters and underscores.")

        # Make sure options are compatable
        if initial and (added_model_list or added_field_list or auto):
            self.error(
                "You cannot use --initial and other options together\n" + self.usage_str)

        if auto and (added_model_list or added_field_list or initial):
            self.error(
                "You cannot use --auto and other options together\n" + self.usage_str)

        if not app:
            self.error(
                "You must provide an app to create a migration for.\n" + self.usage_str)

        # See if the app exists
        app = app.split(".")[-1]
        try:
            app_module = models.get_app(app)
        except ImproperlyConfigured:
            print("There is no enabled application matching '%s'." % app)
            return

        # Get the Migrations for this app (creating the migrations dir if needed)
        migrations = Migrations(app, force_creation=True,
                                verbose_creation=int(verbosity) > 0)

        # What actions do we need to do?
        if auto:
            # Get the old migration
            try:
                last_migration = migrations[-2 if update else -1]
            except IndexError:
                self.error(
                    "You cannot use --auto on an app with no migrations. Try --initial.")
            # Make sure it has stored models
            if migrations.app_label() not in getattr(
                    last_migration.migration_class(), "complete_apps", []):
                self.error(
                    "You cannot use automatic detection, since the previous migration does not have this whole app frozen.\nEither make migrations using '--freeze %s' or set 'SOUTH_AUTO_FREEZE_APP = True' in your settings.py." % migrations.app_label())
            # Alright, construct two model dicts to run the differ on.
            old_defs = dict(
                (k, v) for k, v in
                last_migration.migration_class().models.items()
                if k.split(".")[0] == migrations.app_label()
            )
            new_defs = dict(
                (k, v) for k, v in
                freezer.freeze_apps([migrations.app_label()]).items()
                if k.split(".")[0] == migrations.app_label()
            )
            change_source = changes.AutoChanges(
                migrations=migrations,
                old_defs=old_defs,
                old_orm=last_migration.orm(),
                new_defs=new_defs,
            )

        elif initial:
            # Do an initial migration
            change_source = changes.InitialChanges(migrations)

        else:
            # Read the commands manually off of the arguments
            if (added_model_list or added_field_list or added_index_list):
                change_source = changes.ManualChanges(
                    migrations,
                    added_model_list,
                    added_field_list,
                    added_index_list,
                )
            elif empty:
                change_source = None
            else:
                print(
                    "You have not passed any of --initial, --auto, --empty, --add-model, --add-field or --add-index.",
                    file=sys.stderr)
                sys.exit(1)

        # Validate this so we can access the last migration without worrying
        if update and not migrations:
            self.error("You cannot use --update on an app with no migrations.")

        # if not name, there's an error
        if not name:
            if change_source:
                name = change_source.suggest_name()
            if update:
                name = re.sub(r'^\d{4}_', '', migrations[-1].name())
            if not name:
                self.error(
                    "You must provide a name for this migration\n" + self.usage_str)

        # Get the actions, and then insert them into the actions lists
        forwards_actions = []
        backwards_actions = []

        if change_source:
            for action_name, params in change_source.get_changes():
                # Run the correct Action class
                try:
                    action_class = getattr(actions, action_name)
                except AttributeError:
                    raise ValueError(
                        "Invalid action name from source: %s" % action_name)
                else:
                    action = action_class(**params)
                    action.add_forwards(forwards_actions)
                    action.add_backwards(backwards_actions)
                    print(action.console_line(), file=sys.stderr)

        # Nowt happen? That's not good for --auto.
        if auto and not forwards_actions:
            self.error("Nothing seems to have changed.")

        # Work out which apps to freeze
        apps_to_freeze = self.calc_frozen_apps(migrations, freeze_list)

        # So, what's in this file, then?
        file_contents = MIGRATION_TEMPLATE % {
            "forwards": "\n".join(forwards_actions or ["        pass"]),
            "backwards": "\n".join(backwards_actions or ["        pass"]),
            "frozen_models": freezer.freeze_apps_to_string(apps_to_freeze),
            "complete_apps": apps_to_freeze and "complete_apps = [%s]" % (
                ", ".join(map(repr, apps_to_freeze))) or ""
        }

        # Custom Bluebottle
        # We find and replace the base apps with our mapped models
        for model in MODEL_MAP:
            model_map = MODEL_MAP[model]
            mapping = {
                'u"orm[\'{0}\']"'.format(model_map[
                                             'model']): '"orm[\'{0}\']".format(MODEL_MAP[\'{1}\'][\'model\'])'.format(
                    '{0}', model),
                'u\'{0}\''.format(
                    model_map['table']): 'MODEL_MAP[\'{0}\'][\'table\']'.format(
                    model),
                'u\'{0}\''.format(model_map[
                                      'model_lower']): 'MODEL_MAP[\'{0}\'][\'model_lower\']'.format(
                    model),
                'u\'{0}\''.format(
                    model_map['app']): 'MODEL_MAP[\'{0}\'][\'app\']'.format(
                    model),
                '[\'{0}\']'.format(
                    model_map['app']): '[MODEL_MAP[\'{0}\'][\'app\']]'.format(
                    model),
                'to=orm[\'{0}\']'.format(model_map[
                                             'model']): 'to=orm[MODEL_MAP[\'{0}\'][\'model\']]'.format(
                    model),
                '\'object_name\': \'{0}\''.format(model_map[
                                                      'class']): '\'object_name\': MODEL_MAP[\'{0}\'][\'class\']'.format(
                    model)
            }
            file_contents = reduce(lambda x, y: x.replace(y, mapping[y]),
                                   mapping, file_contents)
        # End Custom Bluebottle

        # Deal with update mode as late as possible, avoid a rollback as long
        # as something else can go wrong.
        if update:
            last_migration = migrations[-1]
            if MigrationHistory.objects.filter(applied__isnull=False,
                                               app_name=app,
                                               migration=last_migration.name()):
                print(
                    "Migration to be updated, %s, is already applied, rolling it back now..." % last_migration.name(),
                    file=sys.stderr)
                migrate_app(migrations, 'current-1', verbosity=verbosity)
            for ext in ('py', 'pyc'):
                old_filename = "%s.%s" % (
                    os.path.join(migrations.migrations_dir(),
                                 last_migration.filename), ext)
                if os.path.isfile(old_filename):
                    os.unlink(old_filename)
            migrations.remove(last_migration)

        # See what filename is next in line. We assume they use numbers.
        new_filename = migrations.next_filename(name)

        # - is a special name which means 'print to stdout'
        if name == "-":
            print(file_contents)
        # Write the migration file if the name isn't -
        else:
            fp = open(os.path.join(migrations.migrations_dir(), new_filename),
                      "w")
            fp.write(file_contents)
            fp.close()
            verb = 'Updated' if update else 'Created'
            if empty:
                print(
                    "%s %s. You must now edit this migration and add the code for each direction." % (
                        verb, new_filename), file=sys.stderr)
            else:
                print(
                    "%s %s. You can now apply this migration with: ./manage.py migrate %s" % (
                        verb, new_filename, app), file=sys.stderr)
예제 #20
0
            print "./manage.py migrate " + self.args
            return
    else:
        apps = list(migration.all_migrations())
        
    # Do we need to show the list of migrations?
    if show_list and apps:
        list_migrations(apps, database, **options)
        
    if not show_list:
            
        for app in apps:
            result = migration.migrate_app(
                app,
                target_name = target,
                fake = fake,
                db_dry_run = db_dry_run,
                verbosity = int(options.get('verbosity', 0)),
                interactive = options.get('interactive', True),
                load_initial_data = not options.get('no_initial_data', False),
                merge = merge,
                skip = skip,
                database = database,
                delete_ghosts = delete_ghosts,
                ignore_ghosts = ignore_ghosts,
            )
            if result is False:
                sys.exit(1) # Migration failed, so the command fails.

Command.handle = new_handle
예제 #21
0
    def test_migration_merge_forwards(self):
        migrations = Migrations("fakeapp")

        # We should start with no migrations
        self.assertEqual(list(MigrationHistory.objects.all()), [])

        # Insert one in the wrong order
        MigrationHistory.objects.create(app_name="fakeapp",
                                        migration="0002_eggs",
                                        applied=datetime.datetime.now())

        # Did it go in?
        self.assertListEqual(
            (("fakeapp", "0002_eggs"), ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Apply them normally
        self.assertRaises(exceptions.InconsistentMigrationHistory,
                          migrate_app,
                          migrations,
                          target_name=None,
                          fake=False)
        self.assertRaises(exceptions.InconsistentMigrationHistory,
                          migrate_app,
                          migrations,
                          target_name='zero',
                          fake=False)
        try:
            migrate_app(migrations, target_name=None, fake=False)
        except exceptions.InconsistentMigrationHistory as e:
            self.assertEqual(
                [(
                    migrations['0002_eggs'],
                    migrations['0001_spam'],
                )],
                e.problems,
            )
        try:
            migrate_app(migrations, target_name="zero", fake=False)
        except exceptions.InconsistentMigrationHistory as e:
            self.assertEqual(
                [(
                    migrations['0002_eggs'],
                    migrations['0001_spam'],
                )],
                e.problems,
            )

        # Nothing should have changed (no merge mode!)
        self.assertListEqual(
            (("fakeapp", "0002_eggs"), ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Apply with merge
        migrate_app(migrations, target_name=None, merge=True, fake=False)

        # We should finish with all migrations
        self.assertListEqual(
            (
                ("fakeapp", "0001_spam"),
                ("fakeapp", "0002_eggs"),
                ("fakeapp", "0003_alter_spam"),
            ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Now roll them backwards
        migrate_app(migrations, target_name="0002", fake=False)
        migrate_app(migrations, target_name="0001", fake=True)
        migrate_app(migrations, target_name="zero", fake=False)

        # Finish with none
        self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #22
0
class Command(BaseCommand):
    option_list = BaseCommand.option_list + (
        make_option('--all',
                    action='store_true',
                    dest='all_apps',
                    default=False,
                    help='Run the specified migration for all apps.'),
        make_option(
            '--list',
            action='store_true',
            dest='show_list',
            default=False,
            help='List migrations noting those that have been applied'),
        make_option('--changes',
                    action='store_true',
                    dest='show_changes',
                    default=False,
                    help='List changes for migrations'),
        make_option('--skip',
                    action='store_true',
                    dest='skip',
                    default=False,
                    help='Will skip over out-of-order missing migrations'),
        make_option(
            '--merge',
            action='store_true',
            dest='merge',
            default=False,
            help=
            'Will run out-of-order missing migrations as they are - no rollbacks.'
        ),
        make_option('--no-initial-data',
                    action='store_true',
                    dest='no_initial_data',
                    default=False,
                    help='Skips loading initial data if specified.'),
        make_option(
            '--fake',
            action='store_true',
            dest='fake',
            default=False,
            help=
            "Pretends to do the migrations, but doesn't actually execute them."
        ),
        make_option(
            '--db-dry-run',
            action='store_true',
            dest='db_dry_run',
            default=False,
            help=
            "Doesn't execute the SQL generated by the db methods, and doesn't store a record that the migration(s) occurred. Useful to test migrations before applying them."
        ),
        make_option(
            '--delete-ghost-migrations',
            action='store_true',
            dest='delete_ghosts',
            default=False,
            help=
            "Tells South to delete any 'ghost' migrations (ones in the database but not on disk)."
        ),
        make_option(
            '--ignore-ghost-migrations',
            action='store_true',
            dest='ignore_ghosts',
            default=False,
            help=
            "Tells South to ignore any 'ghost' migrations (ones in the database but not on disk) and continue to apply new migrations."
        ),
        make_option(
            '--noinput',
            action='store_false',
            dest='interactive',
            default=True,
            help='Tells Django to NOT prompt the user for input of any kind.'),
        make_option('--database',
                    action='store',
                    dest='database',
                    default=DEFAULT_DB_ALIAS,
                    help='Nominates a database to synchronize. '
                    'Defaults to the "default" database.'),
    )
    if '--verbosity' not in [
            opt.get_opt_string() for opt in BaseCommand.option_list
    ]:
        option_list += (make_option(
            '--verbosity',
            action='store',
            dest='verbosity',
            default='1',
            type='choice',
            choices=['0', '1', '2'],
            help=
            'Verbosity level; 0=minimal output, 1=normal output, 2=all output'
        ), )
    help = "Runs migrations for all apps."
    args = "[appname] [migrationname|zero] [--all] [--list] [--skip] [--merge] [--no-initial-data] [--fake] [--db-dry-run] [--database=dbalias]"

    def handle(self,
               app=None,
               target=None,
               skip=False,
               merge=False,
               backwards=False,
               fake=False,
               db_dry_run=False,
               show_list=False,
               show_changes=False,
               database=DEFAULT_DB_ALIAS,
               delete_ghosts=False,
               ignore_ghosts=False,
               **options):

        # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb
        # This code imports any module named 'management' in INSTALLED_APPS.
        # The 'management' module is the preferred way of listening to post_syncdb
        # signals, and since we're sending those out with create_table migrations,
        # we need apps to behave correctly.
        for app_name in settings.INSTALLED_APPS:
            try:
                __import__(app_name + '.management', {}, {}, [''])
            except ImportError, exc:
                msg = exc.args[0]
                if not msg.startswith(
                        'No module named') or 'management' not in msg:
                    raise
        # END DJANGO DUPE CODE

        # if all_apps flag is set, shift app over to target
        if options.get('all_apps', False):
            target = app
            app = None

        # Migrate each app
        if app:
            try:
                apps = [Migrations(app)]
            except NoMigrations:
                print "The app '%s' does not appear to use migrations." % app
                print "./manage.py migrate " + self.args
                return
        else:
            apps = list(migration.all_migrations())

        # Do we need to show the list of migrations?
        if show_list and apps:
            list_migrations(apps, database)

        if show_changes and apps:
            show_migration_changes(apps)

        if not (show_list or show_changes):

            for app in apps:
                result = migration.migrate_app(
                    app,
                    target_name=target,
                    fake=fake,
                    db_dry_run=db_dry_run,
                    verbosity=int(options.get('verbosity', 0)),
                    interactive=options.get('interactive', True),
                    load_initial_data=not options.get('no_initial_data',
                                                      False),
                    merge=merge,
                    skip=skip,
                    database=database,
                    delete_ghosts=delete_ghosts,
                    ignore_ghosts=ignore_ghosts,
                )
                if result is False:
                    sys.exit(1)  # Migration failed, so the command fails.
예제 #23
0
    def test_alter_column_null(self):
        def null_ok(eat_exception=True):
            from django.db import connection, transaction
            # the DBAPI introspection module fails on postgres NULLs.
            cursor = connection.cursor()

            # SQLite has weird now()
            if db.backend_name == "sqlite3":
                now_func = "DATETIME('NOW')"
            # So does SQLServer... should we be using a backend attribute?
            elif db.backend_name == "pyodbc":
                now_func = "GETDATE()"
            elif db.backend_name == "oracle":
                now_func = "SYSDATE"
            else:
                now_func = "NOW()"

            try:
                if db.backend_name == "pyodbc":
                    cursor.execute("SET IDENTITY_INSERT southtest_spam ON;")
                cursor.execute(
                    "INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, NULL, %s, 'whatever');"
                    % now_func)
            except:
                if eat_exception:
                    transaction.rollback()
                    return False
                else:
                    raise
            else:
                cursor.execute("DELETE FROM southtest_spam")
                transaction.commit()
                return True

        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")

        # by default name is NOT NULL
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok())
        self.assertListEqual(
            (
                ("fakeapp", "0001_spam"),
                ("fakeapp", "0002_eggs"),
            ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # after 0003, it should be NULL
        migrate_app(migrations, target_name="0003", fake=False)
        self.assert_(null_ok(False))
        self.assertListEqual(
            (
                ("fakeapp", "0001_spam"),
                ("fakeapp", "0002_eggs"),
                ("fakeapp", "0003_alter_spam"),
            ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # make sure it is NOT NULL again
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok(), 'weight not null after migration')
        self.assertListEqual(
            (
                ("fakeapp", "0001_spam"),
                ("fakeapp", "0002_eggs"),
            ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # finish with no migrations, otherwise other tests fail...
        migrate_app(migrations, target_name="zero", fake=False)
        self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #24
0
    def handle(self,
               app=None,
               target=None,
               skip=False,
               merge=False,
               backwards=False,
               fake=False,
               db_dry_run=False,
               show_list=False,
               show_changes=False,
               database=DEFAULT_DB_ALIAS,
               delete_ghosts=False,
               ignore_ghosts=False,
               **options):

        # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb
        # This code imports any module named 'management' in INSTALLED_APPS.
        # The 'management' module is the preferred way of listening to post_syncdb
        # signals, and since we're sending those out with create_table migrations,
        # we need apps to behave correctly.
        for app_name in settings.INSTALLED_APPS:
            try:
                import_module('.management', app_name)
            except ImportError as exc:
                msg = exc.args[0]
                if not msg.startswith(
                        'No module named') or 'management' not in msg:
                    raise
        # END DJANGO DUPE CODE

        # if all_apps flag is set, shift app over to target
        if options.get('all_apps', False):
            target = app
            app = None

        # Migrate each app
        if app:
            try:
                apps = [Migrations(app)]
            except NoMigrations:
                print("The app '%s' does not appear to use migrations." % app)
                print("./manage.py migrate " + self.args)
                return
        else:
            apps = list(migration.all_migrations())

        # Do we need to show the list of migrations?
        if show_list and apps:
            list_migrations(apps, database, **options)

        if show_changes and apps:
            show_migration_changes(apps)

        if not (show_list or show_changes):

            for app in apps:
                result = migration.migrate_app(
                    app,
                    target_name=target,
                    fake=fake,
                    db_dry_run=db_dry_run,
                    verbosity=int(options.get('verbosity', 0)),
                    interactive=options.get('interactive', True),
                    load_initial_data=not options.get('no_initial_data',
                                                      False),
                    merge=merge,
                    skip=skip,
                    database=database,
                    delete_ghosts=delete_ghosts,
                    ignore_ghosts=ignore_ghosts,
                )
                if result is False:
                    sys.exit(1)  # Migration failed, so the command fails.
예제 #25
0
    def handle(self, *args, **options):

        _auto = options.get('auto', False)
        # Loop through all give apps
        # Or fail as no apps are supplied.
        if len(args) <= 0:
            self.say("No apps supplied")
            exit(1)

        for a in args:
            try:
                module, app = self.app_label_to_app_module(a)

                #print "Objects", module, app
            except ImproperlyConfigured as (e):
                module, app = None, None
                self.say("App '%s' could not be found." % a)

            if app:
                me = self.migrations_exist(module)
                if me:
                    self.say("Auto migrations for %s" % a)
                    _auto = True
                else:
                    self.say("New migrations for %s" % a)
                    _auto = False

                if _auto == True:
                    _initial = False
                else:
                    _initial = True
                from django.core import management

                options.update({'initial': _initial, 'auto': _auto})
                p = str(a)

                try:
                    management.call_command('schemamigration', p, **options)
                finally:
                    from south.migration import Migration, Migrations
                    # Migrate each app

                    if a:
                        try:

                            apps = [Migrations(a)]
                            _s = 's'
                            if len(apps) == 1: _s = ''
                            print "Migrating %s app%s in '%s' " % (len(apps),
                                                                   _s, a)

                            for app in apps:
                                result = migration.migrate_app(
                                    apps,
                                    target_name=None,
                                    fake=options.get('fake', False),
                                    db_dry_run=options.get(
                                        'db_dry_run', False),
                                    verbosity=int(options.get('verbosity', 0)),
                                    interactive=options.get(
                                        'interactive', True),
                                    load_initial_data=not options.get(
                                        'no_initial_data', False),
                                    merge=options.get('merge', True),
                                    skip=False,
                                    database=options.get(
                                        'database', DEFAULT_DB_ALIAS),
                                    delete_ghosts=options.get(
                                        'delete_ghosts', False),
                                    ignore_ghosts=options.get(
                                        'ignore_ghosts', False),
                                )
                            if result is False:
                                sys.exit(
                                    1
                                )  # Migration failed, so the command fails.
                        except NoMigrations:
                            print "The app '%s' does not appear to use migrations." % app
                            print "./manage.py migrate " + self.args
                            return
                    else:
                        apps = list(migration.all_migrations())
예제 #26
0
            return
    else:
        apps = list(migration.all_migrations())

    # Do we need to show the list of migrations?
    if show_list and apps:
        list_migrations(apps, database, **options)

    if not show_list:

        for app in apps:
            result = migration.migrate_app(
                app,
                target_name=target,
                fake=fake,
                db_dry_run=db_dry_run,
                verbosity=int(options.get('verbosity', 0)),
                interactive=options.get('interactive', True),
                load_initial_data=not options.get('no_initial_data', False),
                merge=merge,
                skip=skip,
                database=database,
                delete_ghosts=delete_ghosts,
                ignore_ghosts=ignore_ghosts,
            )
            if result is False:
                sys.exit(1)  # Migration failed, so the command fails.


Command.handle = new_handle
예제 #27
0
            self.assertEqual(
                [(
                    migrations['0002_eggs'],
                    migrations['0001_spam'],
                )],
                e.problems,
            )

        # Nothing should have changed (no merge mode!)
        self.assertListEqual(
            ((u"fakeapp", u"0002_eggs"), ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Apply with merge
        migrate_app(migrations, target_name=None, merge=True, fake=False)

        # We should finish with all migrations
        self.assertListEqual(
            (
                (u"fakeapp", u"0001_spam"),
                (u"fakeapp", u"0002_eggs"),
                (u"fakeapp", u"0003_alter_spam"),
            ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Now roll them backwards
        migrate_app(migrations, target_name="0002", fake=False)
        migrate_app(migrations, target_name="0001", fake=True)
        migrate_app(migrations, target_name="zero", fake=False)
예제 #28
0
 def handle(self, *args, **options):
     
     
     _auto = options.get('auto', False)
     # Loop through all give apps 
     # Or fail as no apps are supplied.
     if len(args) <= 0:
         self.say("No apps supplied")
         exit(1)
         
     for a in args:
         try:
             module, app = self.app_label_to_app_module(a)
             
             #print "Objects", module, app
         except ImproperlyConfigured as (e):
             module, app = None, None
             self.say("App '%s' could not be found." % a)
         
         if app:
             me = self.migrations_exist(module)
             if me:
                 self.say("Auto migrations for %s" % a)
                 _auto = True
             else:
                 self.say("New migrations for %s" % a)
                 _auto = False
                 
             if _auto == True:
                 _initial = False
             else:
                 _initial = True
             from django.core import management
             
             options.update({'initial':_initial, 
                'auto':_auto})
             p = str(a)
             
             try:
                 management.call_command('schemamigration', p, **options)
             finally:
                 from south.migration import Migration, Migrations
                 # Migrate each app
                 
                 if a:
                     try:
                         
                         apps = [Migrations(a)]
                         _s = 's'
                         if len(apps) == 1: _s = ''
                         print "Migrating %s app%s in '%s' " % (len(apps), _s,  a)
                          
                         for app in apps:
                             result = migration.migrate_app(
                                 apps,
                                 target_name = None,
                                 fake = options.get('fake', False),
                                 db_dry_run = options.get('db_dry_run', False),
                                 verbosity = int(options.get('verbosity', 0)),
                                 interactive = options.get('interactive', True),
                                 load_initial_data = not options.get('no_initial_data', False),
                                 merge = options.get('merge', True),
                                 skip = False,
                                 database = options.get('database', DEFAULT_DB_ALIAS),
                                 delete_ghosts = options.get('delete_ghosts', False),
                                 ignore_ghosts = options.get('ignore_ghosts', False),
                             )
                         if result is False:
                             sys.exit(1) # Migration failed, so the command fails.
                     except NoMigrations:
                         print "The app '%s' does not appear to use migrations." % app
                         print "./manage.py migrate " + self.args
                         return
                 else:
                     apps = list(migration.all_migrations())
예제 #29
0
class TestMigrationLogic(Monkeypatcher):
    """
    Tests if the various logic functions in migration actually work.
    """

    installed_apps = ["fakeapp", "otherfakeapp"]

    def assertListEqual(self, list1, list2):
        list1 = list(list1)
        list2 = list(list2)
        list1.sort()
        list2.sort()
        return self.assertEqual(list1, list2)

    def test_find_ghost_migrations(self):
        pass

    def test_apply_migrations(self):
        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")

        # We should start with no migrations
        self.assertEqual(list(MigrationHistory.objects.all()), [])

        # Apply them normally
        migrate_app(migrations,
                    target_name=None,
                    fake=False,
                    load_initial_data=True)

        # We should finish with all migrations
        self.assertListEqual(
            (
                (u"fakeapp", u"0001_spam"),
                (u"fakeapp", u"0002_eggs"),
                (u"fakeapp", u"0003_alter_spam"),
            ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Now roll them backwards
        migrate_app(migrations, target_name="zero", fake=False)

        # Finish with none
        self.assertEqual(list(MigrationHistory.objects.all()), [])

    def test_migration_merge_forwards(self):
        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")

        # We should start with no migrations
        self.assertEqual(list(MigrationHistory.objects.all()), [])

        # Insert one in the wrong order
        MigrationHistory.objects.create(app_name="fakeapp",
                                        migration="0002_eggs",
                                        applied=datetime.datetime.now())

        # Did it go in?
        self.assertListEqual(
            ((u"fakeapp", u"0002_eggs"), ),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # Apply them normally
        self.assertRaises(exceptions.InconsistentMigrationHistory,
                          migrate_app,
                          migrations,
                          target_name=None,
                          fake=False)
        self.assertRaises(exceptions.InconsistentMigrationHistory,
                          migrate_app,
                          migrations,
                          target_name='zero',
                          fake=False)
        try:
            migrate_app(migrations, target_name=None, fake=False)
        except exceptions.InconsistentMigrationHistory, e:
            self.assertEqual(
                [(
                    migrations['0002_eggs'],
                    migrations['0001_spam'],
                )],
                e.problems,
            )
        try:
            migrate_app(migrations, target_name="zero", fake=False)
        except exceptions.InconsistentMigrationHistory, e:
            self.assertEqual(
                [(
                    migrations['0002_eggs'],
                    migrations['0001_spam'],
                )],
                e.problems,
            )
예제 #30
0
    def test_alter_column_null(self):
        
        def null_ok(eat_exception=True):
            from django.db import connection, transaction
            # the DBAPI introspection module fails on postgres NULLs.
            cursor = connection.cursor()
        
            # SQLite has weird now()
            if db.backend_name == "sqlite3":
                now_func = "DATETIME('NOW')"
            # So does SQLServer... should we be using a backend attribute?
            elif db.backend_name == "pyodbc":
                now_func = "GETDATE()"
            elif db.backend_name == "oracle":
                now_func = "SYSDATE"
            else:
                now_func = "NOW()"
            
            try:
                if db.backend_name == "pyodbc":
                    cursor.execute("SET IDENTITY_INSERT southtest_spam ON;")
                cursor.execute("INSERT INTO southtest_spam (id, weight, expires, name) VALUES (100, NULL, %s, 'whatever');" % now_func)
            except:
                if eat_exception:
                    transaction.rollback()
                    return False
                else:
                    raise
            else:
                cursor.execute("DELETE FROM southtest_spam")
                transaction.commit()
                return True

        MigrationHistory.objects.all().delete()
        migrations = Migrations("fakeapp")
        
        # by default name is NOT NULL
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok())
        self.assertListEqual(
            (("fakeapp", "0001_spam"),
             ("fakeapp", "0002_eggs"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )
        
        # after 0003, it should be NULL
        migrate_app(migrations, target_name="0003", fake=False)
        self.assert_(null_ok(False))
        self.assertListEqual(
            (("fakeapp", "0001_spam"),
             ("fakeapp", "0002_eggs"),
             ("fakeapp", "0003_alter_spam"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )

        # make sure it is NOT NULL again
        migrate_app(migrations, target_name="0002", fake=False)
        self.failIf(null_ok(), 'weight not null after migration')
        self.assertListEqual(
            (("fakeapp", "0001_spam"),
             ("fakeapp", "0002_eggs"),),
            MigrationHistory.objects.values_list("app_name", "migration"),
        )
        
        # finish with no migrations, otherwise other tests fail...
        migrate_app(migrations, target_name="zero", fake=False)
        self.assertEqual(list(MigrationHistory.objects.all()), [])
예제 #31
0
             (
                 migrations['0002_eggs'],
                 migrations['0001_spam'],
             )
         ],
         e.problems,
     )
 
 # Nothing should have changed (no merge mode!)
 self.assertListEqual(
     ((u"fakeapp", u"0002_eggs"),),
     MigrationHistory.objects.values_list("app_name", "migration"),
 )
 
 # Apply with merge
 migrate_app(migrations, target_name=None, merge=True, fake=False)
 
 # We should finish with all migrations
 self.assertListEqual(
     ((u"fakeapp", u"0001_spam"),
      (u"fakeapp", u"0002_eggs"),
      (u"fakeapp", u"0003_alter_spam"),),
     MigrationHistory.objects.values_list("app_name", "migration"),
 )
 
 # Now roll them backwards
 migrate_app(migrations, target_name="0002", fake=False)
 migrate_app(migrations, target_name="0001", fake=True)
 migrate_app(migrations, target_name="zero", fake=False)
 
 # Finish with none
예제 #32
0
    def handle(self,
               app=None,
               name="",
               added_model_list=None,
               added_field_list=None,
               freeze_list=None,
               initial=False,
               auto=False,
               stdout=False,
               added_index_list=None,
               verbosity=1,
               empty=False,
               update=False,
               **options):

        # Any supposed lists that are None become empty lists
        added_model_list = added_model_list or []
        added_field_list = added_field_list or []
        added_index_list = added_index_list or []
        freeze_list = freeze_list or []

        # --stdout means name = -
        if stdout:
            name = "-"

        # Only allow valid names
        if re.search('[^_\w]', name) and name != "-":
            self.error(
                "Migration names should contain only alphanumeric characters and underscores."
            )

        # Make sure options are compatable
        if initial and (added_model_list or added_field_list or auto):
            self.error(
                "You cannot use --initial and other options together\n" +
                self.usage_str)

        if auto and (added_model_list or added_field_list or initial):
            self.error("You cannot use --auto and other options together\n" +
                       self.usage_str)

        if not app:
            self.error("You must provide an app to create a migration for.\n" +
                       self.usage_str)

        # See if the app exists
        app = app.split(".")[-1]
        try:
            app_module = models.get_app(app)
        except ImproperlyConfigured:
            print("There is no enabled application matching '%s'." % app)
            return

        # Get the Migrations for this app (creating the migrations dir if needed)
        migrations = Migrations(app,
                                force_creation=True,
                                verbose_creation=int(verbosity) > 0)

        # What actions do we need to do?
        if auto:
            # Get the old migration
            try:
                last_migration = migrations[-2 if update else -1]
            except IndexError:
                self.error(
                    "You cannot use --auto on an app with no migrations. Try --initial."
                )
            # Make sure it has stored models
            if migrations.app_label() not in getattr(
                    last_migration.migration_class(), "complete_apps", []):
                self.error(
                    "You cannot use automatic detection, since the previous migration does not have this whole app frozen.\nEither make migrations using '--freeze %s' or set 'SOUTH_AUTO_FREEZE_APP = True' in your settings.py."
                    % migrations.app_label())
            # Alright, construct two model dicts to run the differ on.
            old_defs = dict(
                (k, v)
                for k, v in last_migration.migration_class().models.items()
                if k.split(".")[0] == migrations.app_label())
            new_defs = dict((k, v) for k, v in freezer.freeze_apps(
                [migrations.app_label()]).items()
                            if k.split(".")[0] == migrations.app_label())
            change_source = changes.AutoChanges(
                migrations=migrations,
                old_defs=old_defs,
                old_orm=last_migration.orm(),
                new_defs=new_defs,
            )

        elif initial:
            # Do an initial migration
            change_source = changes.InitialChanges(migrations)

        else:
            # Read the commands manually off of the arguments
            if (added_model_list or added_field_list or added_index_list):
                change_source = changes.ManualChanges(
                    migrations,
                    added_model_list,
                    added_field_list,
                    added_index_list,
                )
            elif empty:
                change_source = None
            else:
                print(
                    "You have not passed any of --initial, --auto, --empty, --add-model, --add-field or --add-index.",
                    file=sys.stderr)
                sys.exit(1)

        # Validate this so we can access the last migration without worrying
        if update and not migrations:
            self.error("You cannot use --update on an app with no migrations.")

        # if not name, there's an error
        if not name:
            if change_source:
                name = change_source.suggest_name()
            if update:
                name = re.sub(r'^\d{4}_', '', migrations[-1].name())
            if not name:
                self.error("You must provide a name for this migration\n" +
                           self.usage_str)

        # Get the actions, and then insert them into the actions lists
        forwards_actions = []
        backwards_actions = []
        if change_source:
            for action_name, params in change_source.get_changes():
                # Run the correct Action class
                try:
                    action_class = getattr(actions, action_name)
                except AttributeError:
                    raise ValueError("Invalid action name from source: %s" %
                                     action_name)
                else:
                    action = action_class(**params)
                    action.add_forwards(forwards_actions)
                    action.add_backwards(backwards_actions)
                    print(action.console_line(), file=sys.stderr)

        # Nowt happen? That's not good for --auto.
        if auto and not forwards_actions:
            self.error("Nothing seems to have changed.")

        # Work out which apps to freeze
        apps_to_freeze = self.calc_frozen_apps(migrations, freeze_list)

        # So, what's in this file, then?
        file_contents = MIGRATION_TEMPLATE % {
            "forwards":
            "\n".join(forwards_actions or ["        pass"]),
            "backwards":
            "\n".join(backwards_actions or ["        pass"]),
            "frozen_models":
            freezer.freeze_apps_to_string(apps_to_freeze),
            "complete_apps":
            apps_to_freeze and "complete_apps = [%s]" %
            (", ".join(map(repr, apps_to_freeze))) or ""
        }

        # Deal with update mode as late as possible, avoid a rollback as long
        # as something else can go wrong.
        if update:
            last_migration = migrations[-1]
            if MigrationHistory.objects.filter(
                    applied__isnull=False,
                    app_name=app,
                    migration=last_migration.name()):
                print(
                    "Migration to be updated, %s, is already applied, rolling it back now..."
                    % last_migration.name(),
                    file=sys.stderr)
                migrate_app(migrations, 'current-1', verbosity=verbosity)
            for ext in ('py', 'pyc'):
                old_filename = "%s.%s" % (os.path.join(
                    migrations.migrations_dir(), last_migration.filename), ext)
                if os.path.isfile(old_filename):
                    os.unlink(old_filename)
            migrations.remove(last_migration)

        # See what filename is next in line. We assume they use numbers.
        new_filename = migrations.next_filename(name)

        # - is a special name which means 'print to stdout'
        if name == "-":
            print(file_contents)
        # Write the migration file if the name isn't -
        else:
            fp = open(os.path.join(migrations.migrations_dir(), new_filename),
                      "w")
            fp.write(file_contents)
            fp.close()
            verb = 'Updated' if update else 'Created'
            if empty:
                print(
                    "%s %s. You must now edit this migration and add the code for each direction."
                    % (verb, new_filename),
                    file=sys.stderr)
            else:
                print(
                    "%s %s. You can now apply this migration with: ./manage.py migrate %s"
                    % (verb, new_filename, app),
                    file=sys.stderr)