def handle(self, app=None, name="", freeze_list=None, stdout=False, verbosity=1, **options): # Any supposed lists that are None become empty lists 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." ) # if not name, there's an error if not name: self.error("You must provide a name for this migration\n" + self.usage_str) if not app: self.error("You must provide an app to create a migration for.\n" + self.usage_str) # Get the Migrations for this app (creating the migrations dir if needed) migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0) # See what filename is next in line. We assume they use numbers. new_filename = migrations.next_filename(name) # 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 % { "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 "" } # - 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() print("Created %s." % new_filename, file=sys.stderr)
def handle(self, **options): # Resolve dependencies Migrations.calculate_dependencies() print "digraph G {" # Print each app in a cluster #for migrations in all_migrations(): # print " subgraph %s {" % migrations.app_label() # # Nodes inside here are linked # print (" -> ".join(['"%s.%s"' % (migration.app_label(), migration.name()) for migration in migrations])) + ";" # print " }" # For every migration, print its links. for migrations in all_migrations(): for migration in migrations: for other in migration.dependencies: print '"%s.%s" -> "%s.%s"' % ( other.app_label(), other.name(), migration.app_label(), migration.name(), ) print "}"
def skip_migration_if_applied(settings, app_name, table_name, name="0001_initial"): from south.migration import Migrations from sentry.utils.db import table_exists import types if app_name not in settings.INSTALLED_APPS: return migration = Migrations(app_name)[name] def skip_if_table_exists(original): def wrapped(self): # TODO: look into why we're having to return some ridiculous # lambda if table_exists(table_name): return lambda x=None: None return original() wrapped.__name__ = original.__name__ return wrapped migration.forwards = types.MethodType( skip_if_table_exists(migration.forwards), migration)
def setUp(self): super(MigrationTest, self).setUp() self.before_migrations = [] for app_name, version in self.before: migrations = Migrations(app_name) self.before_migrations.append( (app_name, migrations.guess_migration( self._get_migration_number(version)).name())) self.after_migrations = [] for app_name, version in self.after: migrations = Migrations(app_name) self.after_migrations.append( (app_name, migrations.guess_migration( self._get_migration_number(version)).name())) self.before_orm = {} for app_name, version in self.before_migrations: migrations = Migrations(app_name) self.before_orm[app_name] = migrations[version].orm() self.after_orm = {} for app_name, version in self.after_migrations: migrations = Migrations(app_name) self.after_orm[app_name] = migrations[version].orm() for app_name, version in self.before_migrations: # Do a fake migration first to update the migration history. self.migrate(app_name, version=None, fake=True) self.migrate(app_name, version=version)
def handle(self, app=None, *args, **options): # Make sure we have an app if not app: print "Please specify an app to convert." return # 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 # Try to get its list of models model_list = models.get_models(app_module) if not model_list: print "This application has no models; this command is for applications that already have models syncdb'd." print "Make some models, and then use ./manage.py schemamigration %s --initial instead." % app return # Ask South if it thinks it's already got migrations try: Migrations(app) except NoMigrations: pass else: print "This application is already managed by South." return # Finally! It seems we've got a candidate, so do the two-command trick verbosity = int(options.get('verbosity', 0)) management.call_command("schemamigration", app, initial=True, verbosity=verbosity) # Now, we need to re-clean and sanitise appcache hacks.clear_app_cache() hacks.repopulate_app_cache() # And also clear our cached Migration classes Migrations._clear_cache() # Now, migrate management.call_command( "migrate", app, "0001", fake=True, verbosity=verbosity, ignore_ghosts=options.get("ignore_ghosts", False), delete_ghosts=options.get("delete_ghosts", False), ) print print "App '%s' converted. Note that South assumed the application's models matched the database" % app print "(i.e. you haven't changed it since last syncdb); if you have, you should delete the %s/migrations" % app print "directory, revert models.py so it matches the database, and try again."
def test_south_migrations(self): from django.core.exceptions import ImproperlyConfigured from django.conf import settings from django.db import models from south.migration import Migrations, migrate_app from south.models import MigrationHistory from south.exceptions import NoMigrations from south.creator import changes, actions, freezer from south.management.commands.datamigration import Command as DataCommand apps = [app for app in settings.INSTALLED_APPS if app.startswith('wagtail.')] failing_apps = [] for app_name in apps: app = app_name.split('.')[-1] try: models.get_app(app) except ImproperlyConfigured: # This module fails to load, probably because it has no # models.py. Ignore it and move on continue try: migrations = Migrations(app, force_creation=False, verbose_creation=False) last_migration = migrations[-1] except (NoMigrations, IndexError): # No migrations for this app, probably doesnt have models continue if migrations.app_label() not in getattr(last_migration.migration_class(), "complete_apps", []): self.fail("Automatic migrations checking failed, 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, ) name = 'test' # Get the actions, and then insert them into the actions lists if list(change_source.get_changes()): failing_apps.append(app_name) if failing_apps: self.fail('Model changes with no South migration detected in apps: %s' % ( ', '.join(failing_apps)))
def handle(self, app=None, *args, **options): # Make sure we have an app if not app: print("Please specify an app to convert.") return # 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 # Try to get its list of models model_list = models.get_models(app_module) if not model_list: print("This application has no models; this command is for applications that already have models syncdb'd.") print("Make some models, and then use ./manage.py schemamigration %s --initial instead." % app) return # Ask South if it thinks it's already got migrations try: Migrations(app) except NoMigrations: pass else: print("This application is already managed by South.") return # Finally! It seems we've got a candidate, so do the two-command trick verbosity = int(options.get('verbosity', 0)) management.call_command("schemamigration", app, initial=True, verbosity=verbosity) # Now, we need to re-clean and sanitise appcache hacks.clear_app_cache() hacks.repopulate_app_cache() # And also clear our cached Migration classes Migrations._clear_cache() # Now, migrate management.call_command( "migrate", app, "0001", fake=True, verbosity=verbosity, ignore_ghosts=options.get("ignore_ghosts", False), delete_ghosts=options.get("delete_ghosts", False), ) print() print("App '%s' converted. Note that South assumed the application's models matched the database" % app) print("(i.e. you haven't changed it since last syncdb); if you have, you should delete the %s/migrations" % app) print("directory, revert models.py so it matches the database, and try again.")
def _south_migrate_all(): if not 'south' in settings.INSTALLED_APPS: sys.stderr.write( "warning: 'south' is not in INSTALLED_APPS, no migration done.\n") return 0 #pylint: disable=import-error,too-many-nested-blocks from south.migration import Migrations from south.management.commands import migrate schema_cmd = SchemaMigration() initial_apps = [] auto_apps = [] #pylint: disable=unused-variable for app in [app for app in settings.INSTALLED_APPS if app != 'south']: try: app_module = models.get_app(app) #pylint: disable=no-member # South only used with Django < 1.7 clsmembers = inspect.getmembers(app_module, is_model_class) if clsmembers: migrations_dir = os.path.join( os.path.dirname(app_module.__file__), 'migrations') if os.path.isdir(migrations_dir): schema_cmd.handle(app, auto=True)#pylint:disable=no-member found = False for migration_file in os.listdir(migrations_dir): if (re.match(r'^\d\d\d\d', migration_file) and not migration_file.startswith('0001_initial')): found = True break if found: auto_apps += [app] else: initial_apps += [app] else: schema_cmd.handle( #pylint:disable=no-member app, initial=True) initial_apps += [app] else: sys.stderr.write( "warning: App %s does not seem to contain any Model\n" % app) except OSError as err: sys.stderr.write("error: App %s, %s\n" % (app, err)) except RuntimeError as err: sys.stderr.write("error: App %s, %s\n" % (app, err)) except ImproperlyConfigured: sys.stderr.write( "warning: App %s does not seem to contain a models.py\n" % app) # Clear the cached Migrations instances now that we have more of them. Migrations._clear_cache() #pylint: disable=no-member,protected-access migrate_cmd = migrate.Command() for app in initial_apps: sys.stderr.write("initial migrate for %s\n" % app) migrate_cmd.handle(app, fake=True) sys.stderr.write("MIGRATE ALL!\n") migrate_cmd.handle(no_initial_data=True) return 0
def get_indexes(self): # TODO: не удаляются индексы у внешних ключей и добавочные # _like-индексы к ним. Например у House migration = Migrations('fias', force_creation=True) # получим текущее состояние базы new_defs = dict( (k, v) for k, v in freezer.freeze_apps([migration.app_label()]).items() if k.split(".")[0] == migration.app_label()) # скопируем и удалим все индексы old_defs = copy.deepcopy(new_defs) for table in old_defs.values(): for key, value in table.items(): # удалим 'index_together' if key == 'Meta' and 'index_together' in value: del value['index_together'] if isinstance(value, tuple): # удалим 'unique' if 'unique' in value[2]: value[2]['unique'] = False # удалим 'db_index' if 'db_index' in value[2]: value[2]['db_index'] = False class InitialMigration(SchemaMigration): def forwards(self, orm): pass def backwards(self, orm): pass models = old_defs complete_apps = ['fias'] initial_orm = FakeORM(InitialMigration, "fias") # получим все изменения, т.е. список индексов change_source = changes.AutoChanges( migrations=migration, old_defs=old_defs, old_orm=initial_orm, new_defs=new_defs, ) for action_name, params in change_source.get_changes(): try: action_class = getattr(actions, action_name) except AttributeError: raise ValueError("Invalid action name from source: %s" % action_name) else: if issubclass(action_class, AddUnique): yield action_class, params
def handle(self, app=None, name="", freeze_list=None, stdout=False, verbosity=1, **options): verbosity = int(verbosity) # Any supposed lists that are None become empty lists 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.") # If not name, there's an error if not name: self.error("You must provide a name for this migration.\n" + self.usage_str) if not app: self.error("You must provide an app to create a migration for.\n" + self.usage_str) # Ensure that verbosity is not a string (Python 3) try: verbosity = int(verbosity) except ValueError: self.error("Verbosity must be an number.\n" + self.usage_str) # Get the Migrations for this app (creating the migrations dir if needed) migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0) # See what filename is next in line. We assume they use numbers. new_filename = migrations.next_filename(name) # 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 = self.get_migration_template() % { "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 "" } # - 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() print("Created %s." % new_filename, file=sys.stderr)
def testGenerateSouthMigration(self): tmp = StringIO.StringIO() sys.stdout = tmp sys.stderr = tmp management.call_command( "schemamigration", "arm_access_support", "-", initial=True, ) migrations = Migrations("arm_access_support") shutil.rmtree(migrations.migrations_dir()) sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__
def migratable(app): try: if south_ok: Migrations(app) return True except (NoMigrations, ImproperlyConfigured): pass return False
def get_migrations(): "Clears migration cache and gets migrations for the test app" from south.migration import Migrations clear_migrations() return Migrations( tagulous_tests_migration, force_creation=True, verbose_creation=False )
def handle(self, **options): # Resolve dependencies Migrations.calculate_dependencies() colors = ['crimson', 'darkgreen', 'darkgoldenrod', 'navy', 'brown', 'darkorange', 'aquamarine', 'blueviolet'] color_index = 0 wrapper = textwrap.TextWrapper(width=40) print("digraph G {") # Group each app in a subgraph for migrations in all_migrations(): print(" subgraph %s {" % migrations.app_label()) print(" node [color=%s];" % colors[color_index]) for migration in migrations: # Munge the label - text wrap and change _ to spaces label = "%s - %s" % ( migration.app_label(), migration.name()) label = re.sub(r"_+", " ", label) label = "\\n".join(wrapper.wrap(label)) print(' "%s.%s" [label="%s"];' % ( migration.app_label(), migration.name(), label)) print(" }") color_index = (color_index + 1) % len(colors) # For every migration, print its links. for migrations in all_migrations(): for migration in migrations: for other in migration.dependencies: # Added weight tends to keep migrations from the same app # in vertical alignment attrs = "[weight=2.0]" # But the more interesting edges are those between apps if other.app_label() != migration.app_label(): attrs = "[style=bold]" print(' "%s.%s" -> "%s.%s" %s;' % ( other.app_label(), other.name(), migration.app_label(), migration.name(), attrs )) print("}");
def handle(self, **options): # Resolve dependencies Migrations.calculate_dependencies() colors = [ 'crimson', 'darkgreen', 'darkgoldenrod', 'navy', 'brown', 'darkorange', 'aquamarine' , 'blueviolet' ] color_index = 0 wrapper = textwrap.TextWrapper(width=40) print("digraph G {") # Group each app in a subgraph for migrations in all_migrations(): print(" subgraph %s {" % migrations.app_label()) print(" node [color=%s];" % colors[color_index]) for migration in migrations: # Munge the label - text wrap and change _ to spaces label = "%s - %s" % ( migration.app_label(), migration.name()) label = re.sub(r"_+", " ", label) label= "\\n".join(wrapper.wrap(label)) print(' "%s.%s" [label="%s"];' % ( migration.app_label(), migration.name(), label)) print(" }") color_index = (color_index + 1) % len(colors) # For every migration, print its links. for migrations in all_migrations(): for migration in migrations: for other in migration.dependencies: # Added weight tends to keep migrations from the same app # in vertical alignment attrs = "[weight=2.0]" # But the more interesting edges are those between apps if other.app_label() != migration.app_label(): attrs = "[style=bold]" print(' "%s.%s" -> "%s.%s" %s;' % ( other.app_label(), other.name(), migration.app_label(), migration.name(), attrs )) print("}");
def handle(self, app=None, name="", freeze_list=None, stdout=False, verbosity=1, **options): # Any supposed lists that are None become empty lists freeze_list = freeze_list or [] fixtures = options.get('fixtures', ['blogs.json']) # --stdout means name = - if options.get('stdout', None): name = "-" # Only allow valid names if re.search('[^_\w]', name) and name != "-": self.error("Migration names should contain only alphanumeric characters and underscores.") # if not name, there's an error if not name: self.error("You must provide a name for this migration\n" + self.usage_str) if not app: self.error("You must provide an app to create a migration for.\n" + self.usage_str) # Get the Migrations for this app (creating the migrations dir if needed) migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0) # See what filename is next in line. We assume they use numbers. new_filename = migrations.next_filename(name) # 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 % { "fixutres": ",".join(fixtures), "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 "" } # - 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() print >>sys.stderr, "Created %s." % new_filename
def skip_migration_if_applied(settings, app_name, table_name, name='0001_initial'): from south.migration import Migrations import types migration = Migrations(app_name)[name] def skip_if_table_exists(original): def wrapped(self): # TODO: look into why we're having to return some ridiculous # lambda if table_exists(table_name): return lambda x=None: None return original() wrapped.__name__ = original.__name__ return wrapped migration.forwards = types.MethodType( skip_if_table_exists(migration.forwards), migration)
def _pick_migration(self, migration_name): """ This method will pick a migration object from the catalogue app """ migrations = Migrations('platform') for migration in migrations: if migration.full_name().split('.')[-1] == migration_name: return migration return None
def makemigrations(application, merge=False, dry_run=False, empty=False, extra_applications=None): """ Generate migrations (for both south and django 1.7+) """ from django.core.exceptions import DjangoRuntimeWarning, ImproperlyConfigured from django.core.management import call_command apps = [application] if extra_applications: apps += extra_applications if DJANGO_1_6: from south.exceptions import NoMigrations from south.migration import Migrations if merge: raise DjangoRuntimeWarning( u'Option not implemented for Django 1.6 and below') for app in apps: try: if not Migrations(app): raise NoMigrations(app) except NoMigrations: print('ATTENTION: No migrations found for {0}, ' 'creating initial migrations.'.format(app)) try: call_command('schemamigration', *(app, ), initial=True, empty=empty) except SystemExit: pass except ImproperlyConfigured: print('WARNING: The app: {0} could not be found.'.format(app)) else: try: call_command('schemamigration', *(app, ), auto=True, empty=empty) except SystemExit: pass else: for app in apps: call_command('makemigrations', *(app, ), merge=merge, dry_run=dry_run, empty=empty)
def setUp(self): super(MigrationTest, self).setUp() self.before_migrations = [] for app_name, version in self.before: migrations = Migrations(app_name) self.before_migrations.append((app_name, migrations.guess_migration( self._get_migration_number(version)).name())) self.after_migrations = [] for app_name, version in self.after: migrations = Migrations(app_name) self.after_migrations.append((app_name, migrations.guess_migration( self._get_migration_number(version)).name())) self.before_orm = {} for app_name, version in self.before_migrations: migrations = Migrations(app_name) self.before_orm[app_name] = migrations[version].orm() self.after_orm = {} for app_name, version in self.after_migrations: migrations = Migrations(app_name) self.after_orm[app_name] = migrations[version].orm() for app_name, version in self.before_migrations: # Do a fake migration first to update the migration history. self.migrate(app_name, version=None, fake=True) self.migrate(app_name, version=version)
def setUp(self): super(SouthMigrationTestCase, self).setUp() migrations = Migrations(self.django_application) self.start_orm = migrations[self.start_migration].orm() self.dest_orm = migrations[self.dest_migration].orm() # Ensure the migration history is up-to-date with a fake migration. # The other option would be to use the south setting for these tests # so that the migrations are used to setup the test db. call_command('migrate', self.django_application, fake=True, verbosity=0) # Then migrate back to the start migration. call_command('migrate', self.django_application, self.start_migration, verbosity=0)
def handle(self, app_name=None, **options): self.options = options if app_name is None: print('No app_label given') return migrations = Migrations(app_name) rebase_plan = self.split_migrations(migrations) if not rebase_plan.migrations: print('No migrations to rebase') return diffs = [] for plan_elem in rebase_plan.migrations: """Prepare diffs""" diffs.append( self.diff_frozen_models(plan_elem['previous'], plan_elem['migration'])) prev_migration = rebase_plan.onto self.prepare_file_cache() for diff, migration in zip(diffs, (m['migration'] for m in rebase_plan.migrations)): """Rebase - rename migrations and apply diffs""" # Prepare new name for migration last_migration_no, _ = split_migration_name(prev_migration.name()) _, migration_base_name = split_migration_name(migration.name()) migration_path = self.find_migration_path(migration) migration_dir = os.path.dirname(migration_path) new_migration_filename = '%04i_%s.py' % (last_migration_no + 1, migration_base_name) new_migration_path = os.path.join(migration_dir, new_migration_filename) # patch migration tree new_migration_tree = self.get_updated_migration(migration, prev_migration, diff=diff) self.write_file(new_migration_path, unicode(new_migration_tree).encode('utf-8')) self.remove_file(migration_path) prev_migration = migration self.flush_file_cache()
def handle(self, **options): # Resolve dependencies Migrations.calculate_dependencies() print "digraph G {" # Print each app in a cluster #for migrations in all_migrations(): # print " subgraph %s {" % migrations.app_label() # # Nodes inside here are linked # print (" -> ".join(['"%s.%s"' % (migration.app_label(), migration.name()) for migration in migrations])) + ";" # print " }" # For every migration, print its links. for migrations in all_migrations(): for migration in migrations: for other in migration.dependencies: print '"%s.%s" -> "%s.%s"' % ( other.app_label(), other.name(), migration.app_label(), migration.name(), ) print "}";
def handle(self, app=None, name="", freeze_list=None, stdout=False, verbosity=1, **options): # Any supposed lists that are None become empty lists freeze_list = freeze_list or [] # --stdout means name = - if stdout: name = "-" # if not name, there's an error if not name: self.error("You must provide a name for this migration\n" + self.usage_str) if not app: self.error("You must provide an app to create a migration for.\n" + self.usage_str) # Get the Migrations for this app (creating the migrations dir if needed) try: migrations = Migrations(app) except NoMigrations: Migrations.create_migrations_directory(app, verbose=verbosity > 0) migrations = Migrations(app) # See what filename is next in line. We assume they use numbers. new_filename = migrations.next_filename(name) # 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 % { "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 "" } # - 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() print >>sys.stderr, "Created %s." % new_filename
def _check_migrations_applied(): """Checks that all south migrations have been applied. """ APP_NAME = 'main' all_migrations = Migrations(APP_NAME) applied_migrations = [ migration.get_migration() for migration in MigrationHistory.objects.filter(app_name=APP_NAME) ] not_applied = set(all_migrations) - set(applied_migrations) if len(not_applied): raise AssertionError("Database migration required. " "Please run `./manage.py migrate main`.\n" "Applied: {applied}\n" "Missing: {not_applied}\n".format( applied=applied_migrations, not_applied=not_applied))
def handle(self, check_app_name=None, **options): runner = simple.DjangoTestSuiteRunner(verbosity=0) err_msg = "Failed to migrate %s; see output for hints at missing dependencies:\n" hacks.patch_flush_during_test_db_creation() failures = 0 if check_app_name is None: app_names = settings.INSTALLED_APPS else: app_names = [check_app_name] for app_name in app_names: app_label = app_name.split(".")[-1] if app_name == 'south': continue try: Migrations(app_name) except (NoMigrations, ImproperlyConfigured): continue app = loading.get_app(app_label) verbosity = int(options.get('verbosity', 1)) if verbosity >= 1: self.stderr.write("processing %s\n" % app_name) old_config = runner.setup_databases() try: call_command('migrate', app_label, noinput=True, verbosity=verbosity) for model in loading.get_models(app): dummy = model._default_manager.exists() except (KeyboardInterrupt, SystemExit): raise except Exception as e: failures += 1 if verbosity >= 1: self.stderr.write(err_msg % app_name) self.stderr.write("%s\n" % e) finally: runner.teardown_databases(old_config) if failures > 0: raise CommandError("Missing depends_on found in %s app(s)." % failures) self.stderr.write("No missing depends_on found.\n")
def handle(self, *args, **options): global command_log global unchanged_count unchanged_count = 0 ok_to_migrate = True force = options.pop('force', False) dry_run = options.pop('dry_run', False) verbosity = int(options.get('verbosity', 1)) # Workaround South's sneaky method of ending commands with error() calls SchemaMigration.error = error_log # Get list of apps that have models which subclass FeinCMSDocument apps_to_migrate = [model._meta.app_label for model in get_subclasses(FeinCMSDocument)] if verbosity: print 'Automatic schema migrations will be created for the following apps:' print '\t%s' % ', '.join(apps_to_migrate) # Exit if running a dry run if dry_run: return # First check if the apps already have migrations for app in apps_to_migrate: try: existing_migrations = Migrations(app, force_creation=False, verbose_creation=False) if not existing_migrations: raise NoMigrations(app) except NoMigrations: if not force: print 'The app "%s" is not tracked by South, either create an initial migration or run this command with "--force" to do so automatically.' % app ok_to_migrate = False # Now migrate the apps if ok_to_migrate: for app in apps_to_migrate: try: SchemaMigration().handle(app, auto=True, interactive=False, **options) except ExitCommand: pass if verbosity > 1: print 'Done. The output from the commands was:\n\t', print '\n\t'.join(command_log) elif verbosity: if unchanged_count == len(apps_to_migrate): print 'No changes detected in any of the above apps.' else: print 'Finished creating migrations.'
def skip_initial_migration_if_applied(settings, app_name, table_name): from south.migration import Migrations import types migrations = Migrations(app_name) # fix the initial migration initial = migrations['0001_initial'] def initial_forwards(original): def wrapped(self): # TODO: look into why we're having to return some ridiculous # lambda if table_exists(table_name): return lambda x=None: None return original() wrapped.__name__ = original.__name__ return wrapped initial.forwards = types.MethodType(initial_forwards(initial.forwards), initial)
else: schema_cmd.handle( #pylint:disable=no-member app, initial=True) initial_apps += [app] else: print("warning: App %s does not seem to contain any Model" % app) except OSError, err: print "error: App %s, %s" % (app, err) except RuntimeError, err: print "warning: App %s, %s" % (app, err) except ImproperlyConfigured: print "warning: App %s does not seem to contain a models.py" % app # Clear the cached Migrations instances now that we have more of them. Migrations._clear_cache() #pylint: disable=no-member,protected-access migrate_cmd = migrate.Command() for app in initial_apps: print "initial migrate for %s" % app migrate_cmd.handle(app, fake=True) print "MIGRATE ALL!" migrate_cmd.handle(no_initial_data=True) return 0 def migrate_all(): """ Create schema migrations for all apps specified in INSTALLED_APPS, then run a migrate command. """ if 'south' in settings.INSTALLED_APPS:
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.
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.
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())
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 = self.get_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)
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, **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 = "-" # 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) # specify the default name 'initial' if a name wasn't specified and we're # doing a migration for an entire app if not name and initial: name = 'initial' # if not name, there's an error if not name: self.error("You must provide a name for this migration\n" + self.usage_str) if not app: self.error("You must provide an app to create a migration for.\n" + self.usage_str) # Get the Migrations for this app (creating the migrations dir if needed) migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0) # See what filename is next in line. We assume they use numbers. new_filename = migrations.next_filename(name) # What actions do we need to do? if auto: # Get the old migration try: last_migration = migrations[-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, ) else: print >>sys.stderr, "You have not passed any of --initial, --auto, --add-model, --add-field or --add-index." sys.exit(1) # Get the actions, and then insert them into the actions lists forwards_actions = [] backwards_actions = [] 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 >>sys.stderr, action.console_line() # 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), "backwards": "\n".join(backwards_actions), "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 "" } # - 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() print >>sys.stderr, "Created %s. You can now apply this migration with: ./manage.py migrate %s" % (new_filename, app)
def migrate(self, target): """ Migrate and return target orm handler. """ call_command('migrate', self.app, target, verbosity=0) return Migrations(self.app).guess_migration(target).orm()
def test_south_migrations(self): from django.core.exceptions import ImproperlyConfigured from django.conf import settings from django.db import models from south.migration import Migrations, migrate_app from south.models import MigrationHistory from south.exceptions import NoMigrations from south.creator import changes, actions, freezer from south.management.commands.datamigration import Command as DataCommand apps = [ app for app in settings.INSTALLED_APPS if app.startswith('wagtail.') ] failing_apps = [] for app_name in apps: app = app_name.split('.')[-1] try: models.get_app(app) except ImproperlyConfigured: # This module fails to load, probably because it has no # models.py. Ignore it and move on continue try: migrations = Migrations(app, force_creation=False, verbose_creation=False) last_migration = migrations[-1] except (NoMigrations, IndexError): # No migrations for this app, probably doesnt have models continue if migrations.app_label() not in getattr( last_migration.migration_class(), "complete_apps", []): self.fail( "Automatic migrations checking failed, 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, ) name = 'test' # Get the actions, and then insert them into the actions lists if list(change_source.get_changes()): failing_apps.append(app_name) if failing_apps: self.fail( 'Model changes with no South migration detected in apps: %s' % (', '.join(failing_apps)))
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.
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, **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) # Get the Migrations for this app (creating the migrations dir if needed) migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0) # What actions do we need to do? if auto: # Get the old migration try: last_migration = migrations[-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 >> sys.stderr, "You have not passed any of --initial, --auto, --empty, --add-model, --add-field or --add-index." sys.exit(1) # if not name, there's an error if not name: if change_source: name = change_source.suggest_name() if not name: self.error("You must provide a name for this migration\n" + self.usage_str) # See what filename is next in line. We assume they use numbers. new_filename = migrations.next_filename(name) # 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 >> sys.stderr, action.console_line() # 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 "" } # - 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() if empty: print >> sys.stderr, "Created %s. You must now edit this migration and add the code for each direction." % new_filename else: print >> sys.stderr, "Created %s. You can now apply this migration with: ./manage.py migrate %s" % ( new_filename, app)
if (not msg.startswith('No module named') and not msg.endswith(' is unknown') ) 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 not show_list: for app in apps: result = migration.migrate_app(
def makemigrations(migrate_plugins=True, merge=False, squash=False): applications = [ # core applications 'cms', 'menus', # testing applications 'meta', 'manytomany_rel', 'fileapp', 'placeholderapp', 'sampleapp', 'fakemlng', 'one_thing', 'extensionapp', 'objectpermissionsapp', 'bunch_of_plugins', 'mti_pluginapp', ] if os.environ.get("AUTH_USER_MODEL") == "emailuserapp.EmailUser": applications.append('emailuserapp') if migrate_plugins: applications.extend([ # official plugins 'djangocms_inherit', 'djangocms_googlemap', 'djangocms_column', 'djangocms_style', 'djangocms_link', 'djangocms_file', 'djangocms_text_ckeditor', 'djangocms_picture', 'djangocms_teaser', 'djangocms_file', 'djangocms_flash', 'djangocms_video', ]) if DJANGO_1_6: from south.exceptions import NoMigrations from south.migration import Migrations if merge: raise DjangoRuntimeWarning( u'Option not implemented for Django 1.6') for application in applications: try: Migrations(application) except NoMigrations: print('ATTENTION: No migrations found for {0}, creating ' 'initial migrations.'.format(application)) try: call_command('schemamigration', application, initial=True) except SystemExit: pass except ImproperlyConfigured: print('WARNING: The app: {0} could not be found.'.format( application)) else: try: call_command('schemamigration', application, auto=True) except SystemExit: pass else: call_command('makemigrations', *applications, merge=merge)
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)
def handle(self, app=None, name="", freeze_list=None, stdout=False, verbosity=1, **options): # Any supposed lists that are None become empty lists 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.") # if not name, there's an error if not name: self.error( "You must provide a name for this migration\n" + self.usage_str) if not app: self.error( "You must provide an app to create a migration for.\n" + self.usage_str) # Get the Migrations for this app (creating the migrations dir if needed) migrations = Migrations(app, force_creation=True, verbose_creation=verbosity > 0) # See what filename is next in line. We assume they use numbers. new_filename = migrations.next_filename(name) # 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 % { "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 # - 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() print("Created %s." % new_filename, file=sys.stderr)