Loading django/core/management/commands/migrate.py +17 −43 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ from collections import OrderedDict from importlib import import_module import itertools import traceback import warnings from django.apps import apps from django.core.management import call_command Loading @@ -13,9 +14,10 @@ from django.core.management.color import no_style from django.core.management.sql import custom_sql_for_model, emit_post_migrate_signal, emit_pre_migrate_signal from django.db import connections, router, transaction, DEFAULT_DB_ALIAS from django.db.migrations.executor import MigrationExecutor from django.db.migrations.loader import MigrationLoader, AmbiguityError from django.db.migrations.loader import AmbiguityError from django.db.migrations.state import ProjectState from django.db.migrations.autodetector import MigrationAutodetector from django.utils.deprecation import RemovedInDjango20Warning from django.utils.module_loading import module_has_submodule Loading Loading @@ -62,7 +64,20 @@ class Command(BaseCommand): # If they asked for a migration listing, quit main execution flow and show it if options.get("list", False): return self.show_migration_list(connection, [options['app_label']] if options['app_label'] else None) warnings.warn( "The 'migrate --list' command is deprecated. Use 'showmigrations' instead.", RemovedInDjango20Warning, stacklevel=2) 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=options.get('stdout', self.stdout), traceback=self.show_traceback, verbosity=self.verbosity, ) # Hook for backends needing any database preparation connection.prepare_database() Loading Loading @@ -325,44 +340,3 @@ class Command(BaseCommand): ) return created_models def show_migration_list(self, connection, app_names=None): """ Shows a list of all migrations on the system, or only those of some named apps. """ # Load migrations from disk/DB loader = MigrationLoader(connection) graph = loader.graph # If we were passed a list of apps, validate it if app_names: invalid_apps = [] for app_name in app_names: if app_name not in loader.migrated_apps: invalid_apps.append(app_name) if invalid_apps: raise CommandError("No migrations present for: %s" % (", ".join(invalid_apps))) # Otherwise, show all apps in alphabetic order else: app_names = sorted(loader.migrated_apps) # For each app, print its migrations in order from oldest (roots) to # newest (leaves). for app_name in app_names: self.stdout.write(app_name, self.style.MIGRATE_LABEL) shown = set() for node in graph.leaf_nodes(app_name): for plan_node in graph.forwards_plan(node): if plan_node not in shown and plan_node[0] == app_name: # Give it a nice title if it's a squashed one title = plan_node[1] if graph.nodes[plan_node].replaces: title += " (%s squashed migrations)" % len(graph.nodes[plan_node].replaces) # Mark it as applied/unapplied if plan_node in loader.applied_migrations: self.stdout.write(" [X] %s" % title) else: self.stdout.write(" [ ] %s" % title) shown.add(plan_node) # If we didn't print anything, then a small message if not shown: self.stdout.write(" (no migrations)", self.style.MIGRATE_FAILURE) django/core/management/commands/showmigrations.py 0 → 100644 +116 −0 Original line number Diff line number Diff line # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.core.management.base import BaseCommand, CommandError from django.db import connections, DEFAULT_DB_ALIAS from django.db.migrations.loader import MigrationLoader class Command(BaseCommand): help = "Shows all available migrations for the current project" def add_arguments(self, parser): parser.add_argument('app_labels', nargs='*', help='App labels of applications to limit the output to.') parser.add_argument('--database', action='store', dest='database', default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. Defaults to the "default" database.') formats = parser.add_mutually_exclusive_group() formats.add_argument('--list', '-l', action='store_const', dest='format', const='list', help='Shows a list of all migrations and which are applied.') formats.add_argument('--plan', '-p', action='store_const', dest='format', const='plan', help='Shows all migrations in the order they will be applied.') parser.set_defaults(format='list') def handle(self, *args, **options): self.verbosity = options.get('verbosity') # Get the database we're operating from db = options.get('database') connection = connections[db] if options['format'] == "plan": return self.show_plan(connection) else: return self.show_list(connection, options['app_labels']) def show_list(self, connection, app_names=None): """ Shows a list of all migrations on the system, or only those of some named apps. """ # Load migrations from disk/DB loader = MigrationLoader(connection) graph = loader.graph # If we were passed a list of apps, validate it if app_names: invalid_apps = [] for app_name in app_names: if app_name not in loader.migrated_apps: invalid_apps.append(app_name) if invalid_apps: raise CommandError("No migrations present for: %s" % (", ".join(invalid_apps))) # Otherwise, show all apps in alphabetic order else: app_names = sorted(loader.migrated_apps) # For each app, print its migrations in order from oldest (roots) to # newest (leaves). for app_name in app_names: self.stdout.write(app_name, self.style.MIGRATE_LABEL) shown = set() for node in graph.leaf_nodes(app_name): for plan_node in graph.forwards_plan(node): if plan_node not in shown and plan_node[0] == app_name: # Give it a nice title if it's a squashed one title = plan_node[1] if graph.nodes[plan_node].replaces: title += " (%s squashed migrations)" % len(graph.nodes[plan_node].replaces) # Mark it as applied/unapplied if plan_node in loader.applied_migrations: self.stdout.write(" [X] %s" % title) else: self.stdout.write(" [ ] %s" % title) shown.add(plan_node) # If we didn't print anything, then a small message if not shown: self.stdout.write(" (no migrations)", self.style.MIGRATE_FAILURE) def show_plan(self, connection): """ Shows all known migrations in the order they will be applied """ # Load migrations from disk/DB loader = MigrationLoader(connection) graph = loader.graph 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: plan.append(graph.nodes[migration]) seen.add(migration) # Output def print_deps(migration): out = [] for dep in migration.dependencies: if dep[1] == "__first__": roots = graph.root_nodes(dep[0]) dep = roots[0] if roots else (dep[0], "__first__") out.append("%s.%s" % dep) if out: return " ... (%s)" % ", ".join(out) return "" for migration in plan: deps = "" if self.verbosity >= 2: deps = print_deps(migration) if (migration.app_label, migration.name) in loader.applied_migrations: self.stdout.write("[X] %s%s" % (migration, deps)) else: self.stdout.write("[ ] %s%s" % (migration, deps)) docs/internals/deprecation.txt +2 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,8 @@ details on these changes. * Private attribute ``django.db.models.Field.related`` will be removed. * The ``--list`` option of the ``migrate`` management command will be removed. .. _deprecation-removed-in-1.9: 1.9 Loading docs/ref/django-admin.txt +29 −8 Original line number Diff line number Diff line Loading @@ -770,15 +770,10 @@ be warned that using ``--fake`` runs the risk of putting the migration state table into a state where manual recovery will be needed to make migrations run correctly. .. django-admin-option:: --list, -l The ``--list`` option will list all of the apps Django knows about, the migrations available for each app and if they are applied or not (marked by an ``[X]`` next to the migration name). Apps without migrations are also included in the list, but will have ``(no migrations)`` printed under them. .. deprecated:: 1.8 The ``--list`` option has been moved to the :djadmin:`showmigrations` command. runfcgi [options] ----------------- Loading Loading @@ -1088,6 +1083,32 @@ behavior you can use the ``--no-startup`` option. e.g.:: django-admin shell --plain --no-startup showmigrations [<app_label> [<app_label>]] ------------------------------------------ .. django-admin:: showmigrations .. versionadded:: 1.8 Shows all migrations in a project. .. django-admin-option:: --list, -l The ``--list`` option lists all of the apps Django knows about, the migrations available for each app, and whether or not each migrations is applied (marked by an ``[X]`` next to the migration name). Apps without migrations are also listed, but have ``(no migrations)`` printed under them. .. django-admin-option:: --plan, -p The ``--plan`` option shows the migration plan Django will follow to apply migrations. Any supplied app labels are ignored because the plan might go beyond those apps. Same as ``--list``, applied migrations are marked by an ``[X]``. For a verbosity of 2 and above, all dependencies of a migration will also be shown. sql <app_label app_label ...> ----------------------------- Loading docs/releases/1.8.txt +10 −0 Original line number Diff line number Diff line Loading @@ -394,6 +394,9 @@ Management Commands * :djadmin:`makemigrations` now supports an :djadminopt:`--exit` option to exit with an error code if no migrations are created. * The new :djadmin:`showmigrations` command allows listing all migrations and their dependencies in a project. Middleware ^^^^^^^^^^ Loading Loading @@ -1134,6 +1137,13 @@ The class :class:`~django.core.management.NoArgsCommand` is now deprecated and will be removed in Django 2.0. Use :class:`~django.core.management.BaseCommand` instead, which takes no arguments by default. Listing all migrations in a project ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``--list`` option of the :djadmin:`migrate` management command is deprecated and will be removed in Django 2.0. Use :djadmin:`showmigrations` instead. ``cache_choices`` option of ``ModelChoiceField`` and ``ModelMultipleChoiceField`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading Loading
django/core/management/commands/migrate.py +17 −43 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ from collections import OrderedDict from importlib import import_module import itertools import traceback import warnings from django.apps import apps from django.core.management import call_command Loading @@ -13,9 +14,10 @@ from django.core.management.color import no_style from django.core.management.sql import custom_sql_for_model, emit_post_migrate_signal, emit_pre_migrate_signal from django.db import connections, router, transaction, DEFAULT_DB_ALIAS from django.db.migrations.executor import MigrationExecutor from django.db.migrations.loader import MigrationLoader, AmbiguityError from django.db.migrations.loader import AmbiguityError from django.db.migrations.state import ProjectState from django.db.migrations.autodetector import MigrationAutodetector from django.utils.deprecation import RemovedInDjango20Warning from django.utils.module_loading import module_has_submodule Loading Loading @@ -62,7 +64,20 @@ class Command(BaseCommand): # If they asked for a migration listing, quit main execution flow and show it if options.get("list", False): return self.show_migration_list(connection, [options['app_label']] if options['app_label'] else None) warnings.warn( "The 'migrate --list' command is deprecated. Use 'showmigrations' instead.", RemovedInDjango20Warning, stacklevel=2) 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=options.get('stdout', self.stdout), traceback=self.show_traceback, verbosity=self.verbosity, ) # Hook for backends needing any database preparation connection.prepare_database() Loading Loading @@ -325,44 +340,3 @@ class Command(BaseCommand): ) return created_models def show_migration_list(self, connection, app_names=None): """ Shows a list of all migrations on the system, or only those of some named apps. """ # Load migrations from disk/DB loader = MigrationLoader(connection) graph = loader.graph # If we were passed a list of apps, validate it if app_names: invalid_apps = [] for app_name in app_names: if app_name not in loader.migrated_apps: invalid_apps.append(app_name) if invalid_apps: raise CommandError("No migrations present for: %s" % (", ".join(invalid_apps))) # Otherwise, show all apps in alphabetic order else: app_names = sorted(loader.migrated_apps) # For each app, print its migrations in order from oldest (roots) to # newest (leaves). for app_name in app_names: self.stdout.write(app_name, self.style.MIGRATE_LABEL) shown = set() for node in graph.leaf_nodes(app_name): for plan_node in graph.forwards_plan(node): if plan_node not in shown and plan_node[0] == app_name: # Give it a nice title if it's a squashed one title = plan_node[1] if graph.nodes[plan_node].replaces: title += " (%s squashed migrations)" % len(graph.nodes[plan_node].replaces) # Mark it as applied/unapplied if plan_node in loader.applied_migrations: self.stdout.write(" [X] %s" % title) else: self.stdout.write(" [ ] %s" % title) shown.add(plan_node) # If we didn't print anything, then a small message if not shown: self.stdout.write(" (no migrations)", self.style.MIGRATE_FAILURE)
django/core/management/commands/showmigrations.py 0 → 100644 +116 −0 Original line number Diff line number Diff line # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.core.management.base import BaseCommand, CommandError from django.db import connections, DEFAULT_DB_ALIAS from django.db.migrations.loader import MigrationLoader class Command(BaseCommand): help = "Shows all available migrations for the current project" def add_arguments(self, parser): parser.add_argument('app_labels', nargs='*', help='App labels of applications to limit the output to.') parser.add_argument('--database', action='store', dest='database', default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. Defaults to the "default" database.') formats = parser.add_mutually_exclusive_group() formats.add_argument('--list', '-l', action='store_const', dest='format', const='list', help='Shows a list of all migrations and which are applied.') formats.add_argument('--plan', '-p', action='store_const', dest='format', const='plan', help='Shows all migrations in the order they will be applied.') parser.set_defaults(format='list') def handle(self, *args, **options): self.verbosity = options.get('verbosity') # Get the database we're operating from db = options.get('database') connection = connections[db] if options['format'] == "plan": return self.show_plan(connection) else: return self.show_list(connection, options['app_labels']) def show_list(self, connection, app_names=None): """ Shows a list of all migrations on the system, or only those of some named apps. """ # Load migrations from disk/DB loader = MigrationLoader(connection) graph = loader.graph # If we were passed a list of apps, validate it if app_names: invalid_apps = [] for app_name in app_names: if app_name not in loader.migrated_apps: invalid_apps.append(app_name) if invalid_apps: raise CommandError("No migrations present for: %s" % (", ".join(invalid_apps))) # Otherwise, show all apps in alphabetic order else: app_names = sorted(loader.migrated_apps) # For each app, print its migrations in order from oldest (roots) to # newest (leaves). for app_name in app_names: self.stdout.write(app_name, self.style.MIGRATE_LABEL) shown = set() for node in graph.leaf_nodes(app_name): for plan_node in graph.forwards_plan(node): if plan_node not in shown and plan_node[0] == app_name: # Give it a nice title if it's a squashed one title = plan_node[1] if graph.nodes[plan_node].replaces: title += " (%s squashed migrations)" % len(graph.nodes[plan_node].replaces) # Mark it as applied/unapplied if plan_node in loader.applied_migrations: self.stdout.write(" [X] %s" % title) else: self.stdout.write(" [ ] %s" % title) shown.add(plan_node) # If we didn't print anything, then a small message if not shown: self.stdout.write(" (no migrations)", self.style.MIGRATE_FAILURE) def show_plan(self, connection): """ Shows all known migrations in the order they will be applied """ # Load migrations from disk/DB loader = MigrationLoader(connection) graph = loader.graph 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: plan.append(graph.nodes[migration]) seen.add(migration) # Output def print_deps(migration): out = [] for dep in migration.dependencies: if dep[1] == "__first__": roots = graph.root_nodes(dep[0]) dep = roots[0] if roots else (dep[0], "__first__") out.append("%s.%s" % dep) if out: return " ... (%s)" % ", ".join(out) return "" for migration in plan: deps = "" if self.verbosity >= 2: deps = print_deps(migration) if (migration.app_label, migration.name) in loader.applied_migrations: self.stdout.write("[X] %s%s" % (migration, deps)) else: self.stdout.write("[ ] %s%s" % (migration, deps))
docs/internals/deprecation.txt +2 −0 Original line number Diff line number Diff line Loading @@ -123,6 +123,8 @@ details on these changes. * Private attribute ``django.db.models.Field.related`` will be removed. * The ``--list`` option of the ``migrate`` management command will be removed. .. _deprecation-removed-in-1.9: 1.9 Loading
docs/ref/django-admin.txt +29 −8 Original line number Diff line number Diff line Loading @@ -770,15 +770,10 @@ be warned that using ``--fake`` runs the risk of putting the migration state table into a state where manual recovery will be needed to make migrations run correctly. .. django-admin-option:: --list, -l The ``--list`` option will list all of the apps Django knows about, the migrations available for each app and if they are applied or not (marked by an ``[X]`` next to the migration name). Apps without migrations are also included in the list, but will have ``(no migrations)`` printed under them. .. deprecated:: 1.8 The ``--list`` option has been moved to the :djadmin:`showmigrations` command. runfcgi [options] ----------------- Loading Loading @@ -1088,6 +1083,32 @@ behavior you can use the ``--no-startup`` option. e.g.:: django-admin shell --plain --no-startup showmigrations [<app_label> [<app_label>]] ------------------------------------------ .. django-admin:: showmigrations .. versionadded:: 1.8 Shows all migrations in a project. .. django-admin-option:: --list, -l The ``--list`` option lists all of the apps Django knows about, the migrations available for each app, and whether or not each migrations is applied (marked by an ``[X]`` next to the migration name). Apps without migrations are also listed, but have ``(no migrations)`` printed under them. .. django-admin-option:: --plan, -p The ``--plan`` option shows the migration plan Django will follow to apply migrations. Any supplied app labels are ignored because the plan might go beyond those apps. Same as ``--list``, applied migrations are marked by an ``[X]``. For a verbosity of 2 and above, all dependencies of a migration will also be shown. sql <app_label app_label ...> ----------------------------- Loading
docs/releases/1.8.txt +10 −0 Original line number Diff line number Diff line Loading @@ -394,6 +394,9 @@ Management Commands * :djadmin:`makemigrations` now supports an :djadminopt:`--exit` option to exit with an error code if no migrations are created. * The new :djadmin:`showmigrations` command allows listing all migrations and their dependencies in a project. Middleware ^^^^^^^^^^ Loading Loading @@ -1134,6 +1137,13 @@ The class :class:`~django.core.management.NoArgsCommand` is now deprecated and will be removed in Django 2.0. Use :class:`~django.core.management.BaseCommand` instead, which takes no arguments by default. Listing all migrations in a project ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``--list`` option of the :djadmin:`migrate` management command is deprecated and will be removed in Django 2.0. Use :djadmin:`showmigrations` instead. ``cache_choices`` option of ``ModelChoiceField`` and ``ModelMultipleChoiceField`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading