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.
This commit is contained in:
Simon Charette 2016-08-20 16:34:06 -04:00
parent ad25fe7350
commit d1757d8df4
5 changed files with 36 additions and 8 deletions

View File

@ -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

View File

@ -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(

View File

@ -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`).

View File

@ -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']
)

View File

@ -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")