16
votes

I would like to know whats the cleanest way to remove all tables for a removed app using Django migrations. If for example I install a new package, I add the app to my settings.py and I do a manage.py makemigrations and a manage.py migrate; when then I decide that I don't want to use this package and I remove it from my settings.py, the command manage.py makemigrations will tell me "no changes detected" and so manage.py migrate will do nothing, but I need to remove the tables that this removed app had created.

I expected Django migrations to handle this so if I remove a app it would also create migrations to remove all the necesary tables.

3
Why don't you remove all migrations first for the app and then remove the app?JuniorCompressor
I changed the question, I explained myself wrong, I hope now its more clear!diegopau
Did you figure out a solution? Having trouble with this as well.John Z

3 Answers

19
votes

you'd have to be careful with this one, make sure you understand the operations being reversed when you do it, but something like this should work:

manage.py migrate <app_name> zero

obviously you have to do this before removing it from your settings and such so migrations are discoverable.

edit: this has slowly been receiving a few upvotes - I figured I'd direct everybody towards the appropriate documentation, in particular:

Use the name zero to unapply all migrations for an app.

3
votes

First, comment out all the classes in your app's models.py. Then, create a new migration as you normally would, which will delete all the app's tables, and run it. Finally, remove the entire app and all references to it from your code base.

3
votes

extending nachouve's answer to a proper django migration, you can use a RunSQL migration with all the DROP statements, see the django migration docs.

You can either put this in the app your about to delete or (if you've already deleted the app or it's installed so you can't edit it) in a different app.

For example to clean up after deleting django-user-accounts (which has poor coverage and is a liability):

from django.db import migrations

DROP_ACCOUNT_TABLES = """\
    DROP TABLE IF EXISTS account_account CASCADE;
    DROP TABLE IF EXISTS account_accountdeletion CASCADE;
    DROP TABLE IF EXISTS account_emailaddress CASCADE;
    DROP TABLE IF EXISTS account_emailconfirmation CASCADE;
    DROP TABLE IF EXISTS account_signupcode CASCADE;
    DROP TABLE IF EXISTS account_signupcoderesult CASCADE;
"""


class Migration(migrations.Migration):

    dependencies = [
        ('auth', '<< previous migations >>'),
    ]

    operations = [
        migrations.RunSQL(DROP_ACCOUNT_TABLES)
    ]