I've made a migration that added a new table and want to revert it and delete the migration, without creating a new migration.
How do I do it? Is there a command to revert last migration and then I can simply delete the migration file?
I've made a migration that added a new table and want to revert it and delete the migration, without creating a new migration.
How do I do it? Is there a command to revert last migration and then I can simply delete the migration file?
You can revert by migrating to the previous migration.
For example, if your last two migrations are:
0010_previous_migration
0011_migration_to_revert
Then you would do:
./manage.py migrate my_app 0010_previous_migration
You can then delete migration 0011_migration_to_revert
.
If you're using Django 1.8+, you can show the names of all the migrations with
./manage.py showmigrations my_app
To reverse all migrations for an app, you can run:
./manage.py migrate my_app zero
The answer by Alasdair covers the basics
./manage.py showmigrations
migrate
using the app name and the migration nameBut it should be pointed out that not all migrations can be reversed. This happens if Django doesn't have a rule to do the reversal. For most changes that you automatically made migrations by ./manage.py makemigrations
, the reversal will be possible. However, custom scripts will need to have both a forward and reverse written, as described in the example here:
https://docs.djangoproject.com/en/1.9/ref/migration-operations/
If you had a RunPython
operation, then maybe you just want to back out the migration without writing a logically rigorous reversal script. The following quick hack to the example from the docs (above link) allows this, leaving the database in the same state that it was after the migration was applied, even after reversing it.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).bulk_create([
Country(name="USA", code="us"),
Country(name="France", code="fr"),
])
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(forwards_func, lambda apps, schema_editor: None),
]
This works for Django 1.8, 1.9
Update: A better way of writing this would be to replace lambda apps, schema_editor: None
with migrations.RunPython.noop
in the snippet above. These are both functionally the same thing. (credit to the comments)
The other thing that you can do is delete the table created manually.
Along with that, you will have to delete that particular migration file. Also, you will have to delete that particular entry in the django-migrations table(probably the last one in your case) which correlates to that particular migration.
I did this in 1.9.1 (to delete the last or latest migration created):
rm <appname>/migrations/<migration #>*
example: rm myapp/migrations/0011*
logged into database and ran this SQL (postgres in this example)
delete from django_migrations where name like '0011%';
I was then able to create new migrations that started with the migration number that I had just deleted (in this case, 11).
Here is my solution, since the above solution do not really cover the use-case, when you use RunPython
.
You can access the table via the ORM with
from django.db.migrations.recorder import MigrationRecorder
>>> MigrationRecorder.Migration.objects.all()
>>> MigrationRecorder.Migration.objects.latest('id')
Out[5]: <Migration: Migration 0050_auto_20170603_1814 for model>
>>> MigrationRecorder.Migration.objects.latest('id').delete()
Out[4]: (1, {u'migrations.Migration': 1})
So you can query the tables and delete those entries that are relevant for you. This way you can modify in detail. With RynPython
migrations you also need to take care of the data that was added/changed/removed. The above example only displays, how you access the table via Djang ORM.
The first part how to "revert migration" has been answered by Alasdair. I will answer:
...delete the migration, without creating a new migration?
TL;DR: You can delete a few last reverted (confused) migrations and make a new one after fixing models. You can use other means to setup to not create a table by migrate command, but the last migration must be created that match the current models.
The "problematic" migration that created an unwanted table is caused by a new Model class that you added.
Why can anyone want to not get a table? How to solve it?
A) No such table should exist in no database on no machine and no conditions
class Meta: abstract = True
B) The table is created rarely, by something else or manually in a special way.
class Meta: managed = False
C) The table is used only on some machine (e.g. in development).
class Meta: managed = some_switch
.D) The project uses multiple databases in settings.DATABASES
allow_migrate
in order to differentiate the databases where the table can or can not be created.(Did I forget something? I expect that everything other worked for you, only the table should not be created. Then e.g. a bug in proxy option of an model can be excluded.)
The migration is created in cases B), C), D) with Django 1.8 and in all cases ABCD with Django 1.9+, but applied to the database only in appropriate cases or maybe never if required so. Migrations has been necessary for running tests since Django 1.8. The complete relevant current state is recorded by migrations even for models with managed=False in Django 1.9+ to be possible to create a ForeignKey between managed/unmanaged models or to can make the model managed=True later. (This question has been written at the time of Django 1.8 mainstream. Everything here should be valid for versions between 1.8 to the current 1.11.)
If you are facing trouble while reverting back the migration, and somehow have messed it, you can perform fake
migrations.
./manage.py migrate <name> --ignore-ghost-migrations --merge --fake
For django version < 1.4 this will create entry in south_migrationhistory
table.
Now you'll be able to revert back the migration easily.
PS: I was stuck for a lot of time and performing fake migration and then reverting back helped me out.