def handle(self, *args, **options): # Get the database we're operating from connection = connections[options['database']] # Load up an executor to get all the migration data executor = MigrationExecutor(connection) # Resolve command-line arguments into a migration app_label, migration_name = options['app_label'], options['migration_name'] if app_label not in executor.loader.migrated_apps: raise CommandError("App '%s' does not have migrations" % app_label) try: migration = executor.loader.get_migration_by_prefix(app_label, migration_name) except AmbiguityError: raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % ( migration_name, app_label)) except KeyError: raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % ( migration_name, app_label)) targets = [(app_label, migration.name)] # Show begin/end around output only for atomic migrations self.output_transaction = migration.atomic # Make a plan that represents just the requested migrations and show SQL # for it plan = [(executor.loader.graph.nodes[targets[0]], options['backwards'])] sql_statements = executor.collect_sql(plan) return '\n'.join(sql_statements)
def handle(self, *args, **options): # Get the database we're operating from db = options.get('database') connection = connections[db] # Load up an executor to get all the migration data executor = MigrationExecutor(connection) # Resolve command-line arguments into a migration if len(args) != 2: raise CommandError("Wrong number of arguments (expecting 'sqlmigrate app_label migrationname')") else: app_label, migration_name = args if app_label not in executor.loader.migrated_apps: raise CommandError("App '%s' does not have migrations" % app_label) try: migration = executor.loader.get_migration_by_prefix(app_label, migration_name) except AmbiguityError: raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % ( migration_name, app_label)) except KeyError: raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % ( migration_name, app_label)) targets = [(app_label, migration.name)] # Make a plan that represents just the requested migrations and show SQL # for it plan = [(executor.loader.graph.nodes[targets[0]], options.get("backwards", False))] sql_statements = executor.collect_sql(plan) for statement in sql_statements: self.stdout.write(statement)
def handle(self, *args, **options): # Get the database we're operating from connection = connections[options['database']] # Load up an executor to get all the migration table_s executor = MigrationExecutor(connection) # Resolve command-line arguments into a migration app_label, migration_name = options['app_label'], options['migration_name'] if app_label not in executor.loader.migrated_apps: raise CommandError("App '%s' does not have migrations" % app_label) try: migration = executor.loader.get_migration_by_prefix(app_label, migration_name) except AmbiguityError: raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % ( migration_name, app_label)) except KeyError: raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % ( migration_name, app_label)) targets = [(app_label, migration.name)] # Show begin/end around output only for atomic migrations self.output_transaction = migration.atomic # Make a plan that represents just the requested migrations and show SQL # for it plan = [(executor.loader.graph.nodes[targets[0]], options['backwards'])] sql_statements = executor.collect_sql(plan) return '\n'.join(sql_statements)
def handle(self, *args, **options): # Get the database we're operating from db = options.get('database') connection = connections[db] # Load up an executor to get all the migration data executor = MigrationExecutor(connection) # Resolve command-line arguments into a migration if len(args) != 2: raise CommandError("Wrong number of arguments (expecting 'sqlmigrate app_label migrationname')") else: app_label, migration_name = args if app_label not in executor.loader.migrated_apps: raise CommandError("App '%s' does not have migrations" % app_label) try: migration = executor.loader.get_migration_by_prefix(app_label, migration_name) except AmbiguityError: raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % ( migration_name, app_label)) except KeyError: raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % ( migration_name, app_label)) targets = [(app_label, migration.name)] # Make a plan that represents just the requested migrations and show SQL # for it plan = [(executor.loader.graph.nodes[targets[0]], options.get("backwards", False))] sql_statements = executor.collect_sql(plan) return '\n'.join(sql_statements)
def as_string_with_sql_annotations(self, *args, **kwargs): connection = connections[DEFAULT_DB_ALIAS] # check allowed engines in settings allowed_engines = get_setting("ALLOW_ENGINES") if allowed_engines and connection.vendor not in allowed_engines: raise Exception("You are not allowed to generate migrations files " "with the DB engine '%s'. Please use an engine among " "the following list: %s" % ( connection.vendor, ", ".join(allowed_engines), )) content = self._original_as_string(*args, **kwargs) assert "\nclass Migration" in content, "couldn't find 'class Migration' in migration content" # write migration un-processed so the executor can find/read it with open(self.path, "w") as f: f.write(content) # get SQL code executor = MigrationExecutor(connection) app_label = self.migration.app_label mirgation_name = self.migration.name plan = [(executor.loader.graph.nodes[(app_label, mirgation_name)], False)] sql_statements = executor.collect_sql(plan) # amend content that will be written to disk comment = "\n".join("# %s" % stmt for stmt in sql_statements) comment = "# Generated SQL code (%s):\n#\n%s\n#\n" % (connection.vendor, comment) # check rules rules = get_setting("RULES") check_results = [] for rule in rules: status = rule().process(self.migration, sql_statements) out = (status, rule.title) check_results.append(out) if check_results: comment += "\n# Check results:\n" for res in check_results: comment += "# CHECK %s: %s\n" % (res[0], res[1]) content = content.replace( "\nclass Migration", "\n%sclass Migration" % comment, ) return content
def handle(self, *args, **options): # Get the database we're operating from connection = connections[options["database"]] # Load up an executor to get all the migration data executor = MigrationExecutor(connection) # Resolve command-line arguments into a migration app_label, migration_name = options["app_label"], options[ "migration_name"] # Validate app_label try: apps.get_app_config(app_label) except LookupError as err: raise CommandError(str(err)) if app_label not in executor.loader.migrated_apps: raise CommandError("App '%s' does not have migrations" % app_label) try: migration = executor.loader.get_migration_by_prefix( app_label, migration_name) except AmbiguityError: raise CommandError( "More than one migration matches '%s' in app '%s'. Please be more specific." % (migration_name, app_label)) except KeyError: raise CommandError( "Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % (migration_name, app_label)) targets = [(app_label, migration.name)] # Show begin/end around output for atomic migrations, if the database # supports transactional DDL. self.output_transaction = (migration.atomic and connection.features.can_rollback_ddl) # Make a plan that represents just the requested migrations and show SQL # for it plan = [(executor.loader.graph.nodes[targets[0]], options["backwards"]) ] sql_statements = executor.collect_sql(plan) if not sql_statements and options["verbosity"] >= 1: self.stderr.write("No operations found.") return "\n".join(sql_statements)
def handle(self, *args, **options): self.verbosity = options.get('verbosity') self.interactive = options.get('interactive') self.show_traceback = options.get('traceback') self.load_initial_data = options.get('load_initial_data') db_dry_run = options.get("db_dry_run") # Get the database we're operating from db = options.get('database') connection = connections[db] # If they asked for a migration listing, quit main execution flow and show it if options.get("list", False): warnings.warn( "The 'migrate --list' command is deprecated. Use 'showmigrations' instead.", RemovedInDjango110Warning, stacklevel=2) self.stdout.ending = None # Remove when #21429 is fixed return call_command( 'showmigrations', '--list', app_labels=[options['app_label']] if options['app_label'] else None, database=db, no_color=options.get('no_color'), settings=options.get('settings'), stdout=self.stdout, traceback=self.show_traceback, verbosity=self.verbosity, ) # Hook for backends needing any database preparation connection.prepare_database() # Work out which apps have migrations and which do not executor = MigrationExecutor(connection, self.migration_progress_callback) # Before anything else, see if there's conflicting apps and drop out # hard if there are any conflicts = executor.loader.detect_conflicts() if conflicts: name_str = "; ".join( "%s in %s" % (", ".join(names), app) for app, names in conflicts.items() ) raise CommandError( "Conflicting migrations detected (%s).\nTo fix them run " "'python manage.py makemigrations --merge'" % name_str ) # If they supplied command line arguments, work out what they mean. run_syncdb = False target_app_labels_only = True if options['app_label'] and options['migration_name']: app_label, migration_name = options['app_label'], options['migration_name'] if app_label not in executor.loader.migrated_apps: raise CommandError( "App '%s' does not have migrations (you cannot selectively " "sync unmigrated apps)" % app_label ) if migration_name == "zero": targets = [(app_label, None)] else: try: migration = executor.loader.get_migration_by_prefix(app_label, migration_name) except AmbiguityError: raise CommandError( "More than one migration matches '%s' in app '%s'. " "Please be more specific." % (migration_name, app_label) ) except KeyError: raise CommandError("Cannot find a migration matching '%s' from app '%s'." % ( migration_name, app_label)) targets = [(app_label, migration.name)] target_app_labels_only = False elif options['app_label']: app_label = options['app_label'] if app_label not in executor.loader.migrated_apps: raise CommandError( "App '%s' does not have migrations (you cannot selectively " "sync unmigrated apps)" % app_label ) targets = [key for key in executor.loader.graph.leaf_nodes() if key[0] == app_label] else: targets = executor.loader.graph.leaf_nodes() run_syncdb = True plan = executor.migration_plan(targets) # Print some useful info if self.verbosity >= 1: self.stdout.write(self.style.MIGRATE_HEADING("Operations to perform:")) if run_syncdb and executor.loader.unmigrated_apps: self.stdout.write( self.style.MIGRATE_LABEL(" Synchronize unmigrated apps: ") + (", ".join(executor.loader.unmigrated_apps)) ) if target_app_labels_only: self.stdout.write( self.style.MIGRATE_LABEL(" Apply all migrations: ") + (", ".join(set(a for a, n in targets)) or "(none)") ) else: if targets[0][1] is None: self.stdout.write(self.style.MIGRATE_LABEL( " Unapply all migrations: ") + "%s" % (targets[0][0], ) ) else: self.stdout.write(self.style.MIGRATE_LABEL( " Target specific migration: ") + "%s, from %s" % (targets[0][1], targets[0][0]) ) # Run the syncdb phase. # If you ever manage to get rid of this, I owe you many, many drinks. # Note that pre_migrate is called from inside here, as it needs # the list of models about to be installed. if run_syncdb and executor.loader.unmigrated_apps: if self.verbosity >= 1: self.stdout.write(self.style.MIGRATE_HEADING("Synchronizing apps without migrations:")) created_models = self.sync_apps(connection, executor.loader.unmigrated_apps) else: created_models = [] emit_pre_migrate_signal([], self.verbosity, self.interactive, connection.alias) # The test runner requires us to flush after a syncdb but before migrations, # so do that here. if options.get("test_flush", False): call_command( 'flush', verbosity=max(self.verbosity - 1, 0), interactive=False, database=db, reset_sequences=False, inhibit_post_migrate=True, ) # Migrate! if self.verbosity >= 1: if db_dry_run: self.stdout.write(self.style.MIGRATE_HEADING("Running migrations dry-run:")) else: self.stdout.write(self.style.MIGRATE_HEADING("Running migrations:")) if not plan: executor.check_replacements() if self.verbosity >= 1: self.stdout.write(" No migrations to apply.") # If there's changes that aren't in migrations yet, tell them how to fix it. autodetector = MigrationAutodetector( executor.loader.project_state(), ProjectState.from_apps(apps), ) changes = autodetector.changes(graph=executor.loader.graph) if changes: self.stdout.write(self.style.NOTICE( " Your models have changes that are not yet reflected " "in a migration, and so won't be applied." )) self.stdout.write(self.style.NOTICE( " Run 'manage.py makemigrations' to make new " "migrations, and then re-run 'manage.py migrate' to " "apply them." )) else: fake = options.get("fake") fake_initial = options.get("fake_initial") if db_dry_run: # Print the SQL without making changes if db_dry_run is set sql_statements = executor.collect_sql(plan) return '\n'.join(sql_statements) else: executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial) # Send the post_migrate signal, so individual apps can do whatever they need # to do at this point. emit_post_migrate_signal(created_models, self.verbosity, self.interactive, connection.alias)
# -*- coding: utf-8 -*-
def generate_changesets_text(connection, app_names=None, author=None, fake=False, skip_errors=False, indent=''): author = author or os.getlogin() loader = MigrationLoader(connection) graph = loader.graph if app_names: validate_app_names(loader, app_names) targets = [key for key in graph.leaf_nodes() if key[0] in app_names] else: targets = graph.leaf_nodes() plan = [] seen = set() # Generate the plan for target in targets: for migration in graph.forwards_plan(target): if migration not in seen: node = graph.node_map[migration] plan.append(node) seen.add(migration) to_generate = [] for node in plan: if node.key not in loader.applied_migrations: to_generate.append(node) executor = MigrationExecutor(connection) def cdata_lines(lines, indentation_level=2): indent_str = indentation_level * indent separator = u'\n%s' % indent_str if len(lines) > 1: return u'\n%s%s\n' % (indent_str, separator.join(lines)) else: return lines[0] outputs = [] changesett = Template( '$indent<changeSet author="$author" id="$id">$body$indent</changeSet>') cdatat = Template('<![CDATA[$body]]>') sqlt = Template('$indent$indent<sql>$body</sql>') rollbackt = Template( '$indent$indent<rollback>\n$indent$body\n$indent$indent</rollback>') forwardt = Template('insert into django_migrations (app, name, applied) ' 'values (\'$app_label\', \'$migration_name\', now())') backwardt = Template('delete from django_migrations where ' 'app=\'$app_label\' and name=\'$migration_name\'') for app_label, name in to_generate: migration = executor.loader.get_migration_by_prefix(app_label, name) targets = [(app_label, migration.name)] forward_plan = [(executor.loader.graph.nodes[targets[0]], False)] backward_plan = [(executor.loader.graph.nodes[targets[0]], True)] try: sql_forward = executor.collect_sql(forward_plan) except Exception as ex: if skip_errors: sql_forward = ['-- skipped due to exception: %s' % ex] else: raise try: sql_backward = executor.collect_sql(backward_plan) except Exception as ex: if skip_errors: sql_backward = ['-- skipped due to exception: %s' % ex] else: raise changeset_id = u'django-%s-%s' % (app_label, migration.name) if fake: changeset_id += '-faked' ctx = { 'indent': indent, 'id': changeset_id, 'author': author, 'app_label': app_label, 'migration_name': migration.name, } def rendertpl(tpl, **extra): tplctx = dict(ctx) tplctx.update(extra) return tpl.substitute(tplctx) changeset_parts = [] if not fake: changeset_parts.append(u'\n' + rendertpl( sqlt, body=rendertpl( cdatat, body=cdata_lines(sql_forward, indentation_level=2) + indent * 2))) changeset_parts.append(rendertpl(sqlt, body=rendertpl(forwardt))) rollback_parts = [] if not fake: rollback_parts.append( rendertpl( sqlt, body=rendertpl( cdatat, body=cdata_lines(sql_backward, indentation_level=3) + indent * 3))) rollback_parts.append(indent + rendertpl(sqlt, body=rendertpl(backwardt))) sep = u'\n' changeset_parts.append( rendertpl(rollbackt, body=sep.join(rollback_parts))) outputs.append( rendertpl(changesett, body=sep.join(changeset_parts) + u'\n')) return u'\n'.join(outputs)
def handle(self, *args, **options): self.verbosity = options.get('verbosity') self.interactive = options.get('interactive') self.show_traceback = options.get('traceback') self.load_initial_data = options.get('load_initial_data') db_dry_run = options.get("db_dry_run") # Get the database we're operating from db = options.get('database') connection = connections[db] # If they asked for a migration listing, quit main execution flow and show it if options.get("list", False): self.stderr.write( "The 'migrate --list' command is deprecated. Use 'showmigrations' instead." ) self.stdout.ending = None # Remove when #21429 is fixed return call_command( 'showmigrations', '--list', app_labels=[options['app_label']] if options['app_label'] else None, database=db, no_color=options.get('no_color'), settings=options.get('settings'), stdout=self.stdout, traceback=self.show_traceback, verbosity=self.verbosity, ) # Hook for backends needing any database preparation connection.prepare_database() # Work out which apps have migrations and which do not executor = MigrationExecutor(connection, self.migration_progress_callback) # Before anything else, see if there's conflicting apps and drop out # hard if there are any conflicts = executor.loader.detect_conflicts() if conflicts: name_str = "; ".join("%s in %s" % (", ".join(names), app) for app, names in conflicts.items()) raise CommandError( "Conflicting migrations detected (%s).\nTo fix them run " "'python manage.py makemigrations --merge'" % name_str) # If they supplied command line arguments, work out what they mean. run_syncdb = False target_app_labels_only = True if options['app_label'] and options['migration_name']: app_label, migration_name = options['app_label'], options[ 'migration_name'] if app_label not in executor.loader.migrated_apps: raise CommandError( "App '%s' does not have migrations (you cannot selectively " "sync unmigrated apps)" % app_label) if migration_name == "zero": targets = [(app_label, None)] else: try: migration = executor.loader.get_migration_by_prefix( app_label, migration_name) except AmbiguityError: raise CommandError( "More than one migration matches '%s' in app '%s'. " "Please be more specific." % (migration_name, app_label)) except KeyError: raise CommandError( "Cannot find a migration matching '%s' from app '%s'." % (migration_name, app_label)) targets = [(app_label, migration.name)] target_app_labels_only = False elif options['app_label']: app_label = options['app_label'] if app_label not in executor.loader.migrated_apps: raise CommandError( "App '%s' does not have migrations (you cannot selectively " "sync unmigrated apps)" % app_label) targets = [ key for key in executor.loader.graph.leaf_nodes() if key[0] == app_label ] else: targets = executor.loader.graph.leaf_nodes() run_syncdb = True plan = executor.migration_plan(targets) # Print some useful info if self.verbosity >= 1: self.stdout.write( self.style.MIGRATE_HEADING("Operations to perform:")) if run_syncdb and executor.loader.unmigrated_apps: self.stdout.write( self.style.MIGRATE_LABEL(" Synchronize unmigrated apps: ") + (", ".join(executor.loader.unmigrated_apps))) if target_app_labels_only: self.stdout.write( self.style.MIGRATE_LABEL(" Apply all migrations: ") + (", ".join(set(a for a, n in targets)) or "(none)")) else: if targets[0][1] is None: self.stdout.write( self.style.MIGRATE_LABEL(" Unapply all migrations: ") + "%s" % (targets[0][0], )) else: self.stdout.write( self.style.MIGRATE_LABEL( " Target specific migration: ") + "%s, from %s" % (targets[0][1], targets[0][0])) # Run the syncdb phase. # If you ever manage to get rid of this, I owe you many, many drinks. # Note that pre_migrate is called from inside here, as it needs # the list of models about to be installed. if run_syncdb and executor.loader.unmigrated_apps: if self.verbosity >= 1: self.stdout.write( self.style.MIGRATE_HEADING( "Synchronizing apps without migrations:")) created_models = self.sync_apps(connection, executor.loader.unmigrated_apps) else: created_models = [] emit_pre_migrate_signal([], self.verbosity, self.interactive, connection.alias) # The test runner requires us to flush after a syncdb but before migrations, # so do that here. if options.get("test_flush", False): call_command( 'flush', verbosity=max(self.verbosity - 1, 0), interactive=False, database=db, reset_sequences=False, inhibit_post_migrate=True, ) # Migrate! if self.verbosity >= 1: if db_dry_run: self.stdout.write( self.style.MIGRATE_HEADING("Running migrations dry-run:")) else: self.stdout.write( self.style.MIGRATE_HEADING("Running migrations:")) if not plan: executor.check_replacements() if self.verbosity >= 1: self.stdout.write(" No migrations to apply.") # If there's changes that aren't in migrations yet, tell them how to fix it. autodetector = MigrationAutodetector( executor.loader.project_state(), ProjectState.from_apps(apps), ) changes = autodetector.changes(graph=executor.loader.graph) if changes: self.stdout.write( self.style.NOTICE( " Your models have changes that are not yet reflected " "in a migration, and so won't be applied.")) self.stdout.write( self.style.NOTICE( " Run 'manage.py makemigrations' to make new " "migrations, and then re-run 'manage.py migrate' to " "apply them.")) else: fake = options.get("fake") fake_initial = options.get("fake_initial") if db_dry_run: # Print the SQL without making changes if db_dry_run is set sql_statements = executor.collect_sql(plan) return '\n'.join(sql_statements) else: executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial) # Send the post_migrate signal, so individual apps can do whatever they need # to do at this point. emit_post_migrate_signal(created_models, self.verbosity, self.interactive, connection.alias)