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:
- Delete the field
population
frommodels.py
. - Create a migration:
python manage.py makemigrations countries_app
- 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:
Nigel222's answer. It will work, but still, will bring an extra migration, just for recreating the field.
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;