diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py index b372369166..d26fd3d88c 100644 --- a/django/core/management/commands/migrate.py +++ b/django/core/management/commands/migrate.py @@ -197,6 +197,7 @@ class Command(BaseCommand): if self.verbosity >= 1: 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. diff --git a/docs/releases/1.8.4.txt b/docs/releases/1.8.4.txt index 070397e885..77ca647ff0 100644 --- a/docs/releases/1.8.4.txt +++ b/docs/releases/1.8.4.txt @@ -24,3 +24,6 @@ Bugfixes * Fixed ``has_changed()`` method in ``contrib.postgres.forms.HStoreField`` (:ticket:`25215`, :ticket:`25233`). + +* Fixed the recording of squashed migrations when running the ``migrate`` + command (:ticket:`25231`). diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py index 02a533aacd..3b05c92ed6 100644 --- a/tests/migrations/test_commands.py +++ b/tests/migrations/test_commands.py @@ -10,6 +10,7 @@ from django.apps import apps from django.core.management import CommandError, call_command from django.db import DatabaseError, connection, models from django.db.migrations import questioner +from django.db.migrations.recorder import MigrationRecorder from django.test import ignore_warnings, mock, override_settings from django.utils import six from django.utils.deprecation import RemovedInDjango110Warning @@ -338,6 +339,51 @@ class MigrateTests(MigrationTestBase): """ call_command("migrate", "migrated_unapplied_app", stdout=six.StringIO()) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + def test_migrate_record_replaced(self): + """ + Running a single squashed migration should record all of the original + replaced migrations as run. + """ + recorder = MigrationRecorder(connection) + out = six.StringIO() + call_command("migrate", "migrations", verbosity=0) + call_command("showmigrations", "migrations", stdout=out, no_color=True) + self.assertEqual( + 'migrations\n' + ' [x] 0001_squashed_0002 (2 squashed migrations)\n', + out.getvalue().lower() + ) + applied_migrations = recorder.applied_migrations() + self.assertIn(("migrations", "0001_initial"), applied_migrations) + self.assertIn(("migrations", "0002_second"), applied_migrations) + self.assertIn(("migrations", "0001_squashed_0002"), applied_migrations) + # Rollback changes + call_command("migrate", "migrations", "zero", verbosity=0) + + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) + def test_migrate_record_squashed(self): + """ + Running migrate for a squashed migration should record as run + if all of the replaced migrations have been run (#25231). + """ + recorder = MigrationRecorder(connection) + recorder.record_applied("migrations", "0001_initial") + recorder.record_applied("migrations", "0002_second") + out = six.StringIO() + call_command("migrate", "migrations", verbosity=0) + call_command("showmigrations", "migrations", stdout=out, no_color=True) + self.assertEqual( + 'migrations\n' + ' [x] 0001_squashed_0002 (2 squashed migrations)\n', + out.getvalue().lower() + ) + self.assertIn( + ("migrations", "0001_squashed_0002"), + recorder.applied_migrations() + ) + # No changes were actually applied so there is nothing to rollback + class MakeMigrationsTests(MigrationTestBase): """