Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Revert Django 1.7 RemoveField migration

If I have a non-nullable model field, remove it, and create a migration, that migration becomes non-reversible:

Consider the following model:

class Foo(models.Model):     bar = models.TextField()     test = models.TextField()  # This field is to go away, bye-bye! 

And migration:

# app/migrations/003_remove_foo_test.py  class Migration(migrations.Migration):      dependencies = [         ('app', '0002_foo_test'),     ]      operations = [         migrations.RemoveField(             model_name='foo',             name='test',         ),     ] 

Unapplying this migration throws an exception:

$ src/manage.py migrate app 0002 Operations to perform:   Target specific migration: 0002_foo_test, from app Running migrations:   Unapplying app.0003_remove_foo_test...Traceback (most recent call last): ... django.db.utils.IntegrityError: column "test" contains null values 

Of course, this is the expected behaviour, it is clearly documented and I'm not asking why this happens:

Bear in mind that when reversed this is actually adding a field to a model; if the field is not nullable this may make this operation irreversible (apart from any data loss, which of course is irreversible).

However, we all make mistakes and sometimes we just need to somehow reverse a field deletion, even if that means manually providing an ad hoc stub value for all reversed non-null fields. For instance, South migrations optionally allow the reversal of such operations (by asking the developer on whether to provide a default for restored fields, or disallow reverse migration), which doesn't seem to be the case with the all new fancy Django 1.7 migrations.

Question: what is the easiest/fastest way to undo a field removal with Django 1.7+ migrations (assuming it has already happened)? It doesn't necessarily need to be fully scripted with Python, a set of manual instructions will do.

like image 956
Ilya Semenov Avatar asked Mar 05 '15 12:03

Ilya Semenov


1 Answers

You can manually edit your migration and add AlterField with default value for a field just before RemoveField. It should be safe even after applying migration. That will make RemoveField that will happen after to be reversible.

An example. Having field in model summary named profit that was defined before removal like that:

profit = models.PositiveIntegerField(verbose_name='profits') 

you should add before RemoveField of it an AlterField like that:

migrations.AlterField(     model_name='summary',     name='profit',     field=models.PositiveIntegerField(verbose_name='profits', default=0),     preserve_default=False,     ), 
like image 200
GwynBleidD Avatar answered Sep 21 '22 17:09

GwynBleidD