Resetting South Migrations
South migrations are great but over time, as you write more and more they can become unwieldy and slow. This is exactly what happened at Streetbook, we love fast iterations and releasing often - the only downside was the number of migrations grew and grew to over a hundred. So we bit the bullet and reset them, it was less traumatic than I initially feared and we got the number of migrations down to just ten. As I couldn't find an easy step by step guide I thought I'd jot this down for others as a quick guide.
Reseting migrations
I found these steps allowed me to reset the migrations quickly and efficiently. First with a fresh db run the existing migrations. Then for each app:
- Export any created data:
./manage.py dumpdata appname --indent=4 > migration_data/app.json
- Delete the old migrations
- Create the initial migration
./manage.py schemamigration appname --initial
- If needed, create a data migration for the app using either:
- fixtures for large datasets
- the south orm
Migration Dependencies
Once you've created all your new migrations run your test suite - its a great way to test the migration chain and will help you sort out dependencies. If building the database for the test suite fails - read the backtrace and look for the migration that caused the failure and then add the correct dependencies code - depends_on / needed_by to the failing migrations.
Circuluar Migrations
Depending on your database structure you might end up with a migration chain that can't be fulfilled due to a circular dependency. I found that we had a couple of instances of Many To Many database tables being created in the initial migrations and those tables relying on one of the tables being created first. So to fix I removed the M2M migrations into their own migration and this cleared the circular dependency.
A word about fixtures
Fixtures can be brilliant and save loads of time, however they bypass the frozen orm and use the schema of the actual model - this can be painful when the model changes in the future. An simple work round I've used in the past has been something like: abusing fixtures in migrations. That worked until I reset the migrations back to a clean state.
Pushing Live
Make sure all the old migrations have been run and you aren't introducing any schema changes with the new migrations - do that before or after you've reset the migrations but not at the same time.
Reset old migrations:
Its simple just mark all the migrations as fake:
./manage.py migrate --all --fake --delete-ghost-migrations
That should work, but this step failed for me saying one initial was applied before its dependency (even though I was faking them.). However, as I was happy with the migration chain - thanks to my trusty test suite I just killed my migration history like so:
from south.models import MigrationHistory MigrationHistory.objects.all().delete()
Then I marked all the migrations as fake:
./manage.py migrate --all --fake
All done!