Django exhibits some internal confusion regarding whether replaced migrations exist or not. Consider this simple app with two migrations and squashed migration replacing both:
$ ls testproj/migrations/
0001_initial.py 0001_squashed_0002_thing_age.py 0002_thing_age.py __init__.py
When it comes to disambiguating input, Django seems to believe that the replaced migrations still need to be considered:
$ ./manage.py migrate testproj 0001
CommandError: More than one migration matches '0001' in app 'testproj'. Please be more specific.
But if you actually try to disambiguate and specify one of the replaced migrations, Django no longer thinks it exists (and isn't very graceful about telling you so):
$ ./manage.py migrate testproj 0001_initial
Traceback (most recent call last):
File "./manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/carljm/projects/django/django/django/django/core/management/__init__.py", line 330, in execute_from_command_line
utility.execute()
File "/home/carljm/projects/django/django/django/django/core/management/__init__.py", line 322, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/carljm/projects/django/django/django/django/core/management/base.py", line 347, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/carljm/projects/django/django/django/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/home/carljm/projects/django/django/django/django/core/management/commands/migrate.py", line 135, in handle
plan = executor.migration_plan(targets)
File "/home/carljm/projects/django/django/django/django/db/migrations/executor.py", line 50, in migration_plan
self.loader.graph.node_map[target].children
KeyError: ('testproj', '0001_initial')
There could be several different approaches to fixing this, but my feeling is that Django shouldn't prevent you from migrating to a replaced migration. If a migration still exists on disk, even if it's been squashed and you've fully migrated the squashed set, you should be able to migrate back to a state within the squashed set. It seems like there might be production rollback cases where that could be important, and I don't see in principle why it shouldn't be possible.
If that turns out to be impractical, then I think Django oughtn't bother you about resolving ambiguities with migration names it won't let you migrate to anyway. And the "nonexistent" error for this case should be nicer than a raw KeyError
. (In Django 1.7 the error was "ValueError: Node ('testproj17', '0001_initial') not a valid node", which is perhaps a bit better, but not much.)
I agree, that should be possible and I think it is possible.