South: how to revert migrations in production server?

2.5k views Asked by At

I want to revert my last migration (0157) by running its Migration.backwards() method. Since I am reverting the migration in production server I want to run it automatically during code deployment. Deployment script executes these steps:

  1. Pull code changes
  2. Run migrations: manage.py migrate <app>
  3. Refresh Apache to use newest code: touch django.wsgi

If I could, I would create new migration file which would tell South to backward migrate to 0156:

migrations/0158_backward__migrate_to_0156.py

This commited migration would be deployed to production and executed during manage.py migrate <app> command. In this case I wouldn't have to execute backward migration by hand, like suggested in these answers.

Lets say, I have created two data migrations, first for user's Payment, second for User model. I have implemented backwards() methods for both migrations in case I'd have to revert these data migrations. I've deployed these two migrations to production. And suddenly find out that Payment migration contains an error. I want to revert my two last data migrations as fast as possible. What is the fastest safe way to do it?

3

There are 3 answers

5
miraculixx On BEST ANSWER

Since I am reverting the migration in production server I want to run it automatically during code deployment.

IMHO the safest path is

  1. run manage.py migrate <app> (i.e. apply all existing migrations, i.e. up to 0156)
  2. undo the changes in your model
  3. run manage.py schemamigration <app> --auto

This will create a new migration 0157 that effectively reverts the previous migration 0156. Then simply apply the new migration by running manage.py migrate <app> again. As I understand, your code deployment will just do that.

4
bruno desthuilliers On

There's no silver bullet here. The simplest solution I can think of would be to - in your dev env of course - manually migrate back to 0156, manually update your migration's history table (sorry I can't remember the table's name now) to fool south in thinking you're still @0158, then run schemamigration again. Not garanteed to work but might be worth trying.

2
Freek Wiekmeijer On

Apparently the codeline has migrations up to #157 and now the developer decided that the last one was not a good idea after all. So the plan is to go back to #156.

Two scenarios:

(a) migration #157 was not released or deployed anywhere yet. Simply revert the last change from models.py and delete migration #157.py from the source archive. Any deployment will take the system to level 156; "157 was never there".

(b) there have been deployments of the latest software with migration #157. In this case the previous strategy will obviously not work. So you need to create a migration #158 to undo #157. Revert the change in models.py and run

django manage.py migrate <app> 0157
django manage.py schemamigration <app> --auto

This will auto-generate a new migration #158, which will contain the inverse schema migration compared to #157.

If schemamigration is giving trouble because of django Model validation (something that can happen if you have custom validators which check stuff outside the ORM box), I suggest the following workaround:

<django project>/<app>/management/commands/checkmigrations.py

from south.management.commands import schemamigration
class Command(schemamigration.Command):
    requires_model_validation = False
    help = "schemamigration without model validation"

This command becomes available in manage.py:

django manage.py checkmigrations <app> --auto