Home > Software engineering >  Is it possible to recreate a table field that was accidentally removed from Django Model, without te
Is it possible to recreate a table field that was accidentally removed from Django Model, without te

Time:10-09

Suppose the following model:

class Country(models.Model):
    name = models.TextField(null=True, blank=True)
    continent = models.TextField(null=True, blank=True)
    population = models.PositiveIntegerField(null=True, blank=True) 

And then I:

  1. Delete the field population from models.py.
  2. Create a migration: python manage.py makemigrations countries_app
  3. Execute the migration, which marks the field as removed: python3 manage.py migrate countries_app

Here's the migration file 0006, which is a sequence for the last migration created (0005):

class Migration(migrations.Migration):

    dependencies = [
        ('countries_app', '0005_auto_20210723_0007'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='country',
            name='population',
        ),
    ]

Now, I don't have the field population on my database, but I realized that it was a mistake, to remove population field from Country model.

Trying to get things back to normal, I define the field once again on the model and I unapply the migration 0006, and also removed 0006 migration file, where it was defined the deletion of the field, and I also execute python manage.py migrate countries_app and it says nothing to migrate, which makes sense.

$ python3 manage.py migrate countries_app
Operations to perform:
  Apply all migrations: countries_app
Running migrations:
  Applying countries_app.0006_remove_country_population... OK

$ rm countries_app/migrations/0006_remove_country_population.py

$ python manage.py migrate countries_app

But when I check the database table, the field population is still not there. I thought Django would recreate it, since I unaplied migration 0006 and the field was once again defined on my model.

I have seen some answers here on SO, instructing something like: unapply all migrations (python manage.py migrate countries_app zero), delete all migration files, create an initial migration once again and then migrate.

That sounds too brutal for me. I'd like to instruct Django to recreate the field that is not there anymore. Is there any efficient and more gentle way of doing this? I'm not that advanced on Django Migrations, so please, bear with me. Thanks.

CodePudding user response:

You can certainly add the field back onto the model and use makemigrations again, then migrate forwards (0006 -> 0007). That will define the column back into the database, but you'll have to repopulate it with valid data. A simple migration will just fill it with a default value.

CodePudding user response:

After some investigation and testing, technically, by unapplying migration 0006 (rolling back to 0005), Django recreates the field that once was deleted. I made local tests with another project, and yes, it's true.

Why rolling back to migration 0005 didn't worked out in my case, it's unknown. I probably messed up something here on my real project. Therefore, as answer, I state that, by rolling back to the previous migration, is normally what you need on these cases.

But, if things are really messed up and Django isn't REcreating the field which once was deleted and now is back again on your model, I see 2 alternatives:

  1. Nigel222's answer. It will work, but still, will bring an extra migration, just for recreating the field.

  2. Connect to the database and manually create the field. This will fix the anomaly that happened, and there'll be no extra migration for solely REcreating a field, which was supposed to be back again on the migration rollback:

ALTER TABLE countries_app_country ADD population INTEGER;
  • Related