Recover deleted Django migrations

6.7k views Asked by At

On my production server I accidentally deleted my migrations directory in one of my apps. Multiple people work on the app, so at the time of making the app, what we did was push up our model changes without making any migrations locally, and than make the migrations on the production server, and migrate there. We did this because we were having migrations merge issues in the past, and thought this might be a good solution. Since there is no local copy of the migrations folder I fear its gone forever. My question is this. I can access phpPgAdmin in Webfaction, and the database has a django_migrations table. I thought one solution would be to find the latest migrations, lets say for example 0009_migration.py, and than simply rename a new migration file, 0010_migration.py for my next migration if I ever make any model changes in the future in that app. That way I can simple run migrate, and it will only be considered with the migration that it has yet to run, 0010_migration.py. But just out of curiosity, is there some command that will look at your PostgreSQL database, and create the migration files in your app migrations directory from the migration records it has on file in the django_migrations table ?

I guess a simpler way to ask this is "Is there a way to reverse engineer django_migrations table rows into migrations.py files ?" Here is an image of a django_migration table row I have in PostgreSQL, and what I would want the file to look like, just with different commands.

Django Migration

class Migration(migrations.Migration):

    dependencies = [
        ('portfolio', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='project',
            name='contact_form',
            field=models.BooleanField(default=False),
        ),
    ]

PostgreSQL django_migrations table row enter image description here

1

There are 1 answers

2
Max M On BEST ANSWER
  1. Delete from the migration table of your database all entires for that one app whose migration files were deleted.

  2. $ python manage.py makemigrations <app>

This creates 1 new migration file (an inital migration).

  1. $ python manage.py migrate <app> --fake

Writes the initial migration into migration table but does not touch any other table (does not actually migrate).

That should work as long as there were no changes to the app whose migration files were deleted.

This might solve the problem of accidently deleting migrations files (assuming they were auto-created by manage.py and not manipulated). But I don't know whether it is able or if it is recommendable to refactor the migrations table - it also might cause to adapt either the auto-creation of migration files, requires the manual manipulation of any migration file after it was auto-created or even requires to override the django backend.

#Edit Answer to the additional question in the comment:

  • The initial $ python manage.py makemigrations <app> creates a migration file that describes the current schemas of all of the models in the given app ($ python manage.py makemigrations does that for all apps).
  • The initial $ python manage.py migrate <app> applies all migration files of the given app to the database and writes to your migration table which migration files were applied by. On initial migrations, all needed database tables with needed attributes and relations will be created ($ python manage.py migrate does that for all apps).
  • Following $ python manage.py makemigrations <app> will create migration files that describes the differences between the latest migration file (so the latest description of the models's schemas in this app) and the current schemas of the models in this app.
  • The migration table of the database simply holds information about which migration files of which apps were applied to the database.
  • Following $ python manage.py migrate <app> will use that migration table to check which migration files has already been applied to the database. If there are migrations files that where not applied, they will be applied and then written to the migration table.

So if you delete the migrations files of an app you just delete the description and history of the models's schemas of that app. Same goes for the entries in your migration table: You just delete information about which migration files where applied to your database.

  • $ manage.py migrate <app> --fake also checks which migration files have to be applied to your database and also writes all migration-files-to-be-applied into your migration table. But this command won't apply them to your database.

So what the actual solution I suggested does is the following:

  1. Delete information about which migration files were applied to your database for one specific app
  2. Create one new migration files of that one app
  3. Write the migration file to the migration table but do not apply it. << This is why there must not be any changes in your app's models since the migration files where deleted.

Why is it necessary to delete existing entries in the migration table?

As you can see in the image you provided in your question, entries in the migration store the name of any applied migration files. Not deleting those entries would cause manage.py migrate assuming migration files with the same name (or number - I'm not 100% aware of this) has already been applied. So those would be skipped on migrations.