From d1757d8df486b689172d2584ded52fad916bcc33 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Sat, 20 Aug 2016 16:34:06 -0400 Subject: [PATCH] Fixed #27044 -- Included already applied migration changes in the post-migrate state when the execution plan is empty. Refs #24100. Thanks tkhyn for the report and Tim for the review. --- django/core/management/commands/migrate.py | 12 ++++++------ django/db/migrations/executor.py | 10 ++++++++-- docs/releases/1.10.1.txt | 4 ++++ tests/migrate_signals/tests.py | 10 ++++++++++ tests/migrations/test_executor.py | 8 ++++++++ 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py index b6c8748bffc..4c8e0083747 100644 --- a/django/core/management/commands/migrate.py +++ b/django/core/management/commands/migrate.py @@ -175,7 +175,6 @@ 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. @@ -194,14 +193,15 @@ class Command(BaseCommand): "migrations, and then re-run 'manage.py migrate' to " "apply them." )) - post_migrate_apps = pre_migrate_apps + fake = False + fake_initial = False else: fake = options['fake'] fake_initial = options['fake_initial'] - post_migrate_project_state = executor.migrate( - targets, plan, fake=fake, fake_initial=fake_initial - ) - post_migrate_apps = post_migrate_project_state.apps + post_migrate_project_state = executor.migrate( + targets, plan, fake=fake, fake_initial=fake_initial + ) + post_migrate_apps = post_migrate_project_state.apps # Re-render models of real apps to include relationships now that # we've got a final state. This wouldn't be necessary if real apps diff --git a/django/db/migrations/executor.py b/django/db/migrations/executor.py index fb9c7a93a41..11a96ec81b4 100644 --- a/django/db/migrations/executor.py +++ b/django/db/migrations/executor.py @@ -82,9 +82,15 @@ class MigrationExecutor(object): all_backwards = all(backwards for mig, backwards in plan) if not plan: - # Nothing to do for an empty plan, except for building the post - # migrate project state + # The resulting state should include applied migrations. state = self._create_project_state() + applied_migrations = { + self.loader.graph.nodes[key] for key in self.loader.applied_migrations + if key in self.loader.graph.nodes + } + for migration, _ in full_plan: + if migration in applied_migrations: + migration.mutate_state(state, preserve=False) elif all_forwards == all_backwards: # This should only happen if there's a mixed plan raise InvalidMigrationPlan( diff --git a/docs/releases/1.10.1.txt b/docs/releases/1.10.1.txt index 3e73483e376..46188aa2da6 100644 --- a/docs/releases/1.10.1.txt +++ b/docs/releases/1.10.1.txt @@ -68,3 +68,7 @@ Bugfixes * Added the database alias to the ``InconsistentMigrationHistory`` message raised by ``makemigrations`` and ``migrate`` (:ticket:`27089`). + +* Fixed the creation of ``ContentType`` and ``Permission`` objects for models + of applications without migrations when calling the ``migrate`` command with + no migrations to apply (:ticket:`27044`). diff --git a/tests/migrate_signals/tests.py b/tests/migrate_signals/tests.py index d422ab84b42..bb3ea0ccc92 100644 --- a/tests/migrate_signals/tests.py +++ b/tests/migrate_signals/tests.py @@ -113,3 +113,13 @@ class MigrateSignalTests(TransactionTestCase): [model._meta.label for model in post_migrate_receiver.call_args['apps'].get_models()], ['migrate_signals.Signal'] ) + # Migrating with an empty plan. + post_migrate_receiver = Receiver(signals.post_migrate) + management.call_command( + 'migrate', database=MIGRATE_DATABASE, verbosity=MIGRATE_VERBOSITY, + interactive=MIGRATE_INTERACTIVE, stdout=stdout, + ) + self.assertEqual( + [model._meta.label for model in post_migrate_receiver.call_args['apps'].get_models()], + ['migrate_signals.Signal'] + ) diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py index b61f51f4571..847b11c088f 100644 --- a/tests/migrations/test_executor.py +++ b/tests/migrations/test_executor.py @@ -168,6 +168,14 @@ class ExecutorTests(MigrationTestBase): ("migrations2", "0001_initial"), ]) self.assertEqual(plan, []) + # The resulting state should include applied migrations. + state = executor.migrate([ + ("migrations", "0002_second"), + ("migrations2", "0001_initial"), + ]) + self.assertIn(('migrations', 'book'), state.models) + self.assertIn(('migrations', 'author'), state.models) + self.assertIn(('migrations2', 'otherauthor'), state.models) # Erase all the fake records executor.recorder.record_unapplied("migrations2", "0001_initial") executor.recorder.record_unapplied("migrations", "0002_second")