Django: find ghost tables without associated models

Heavy refactoring of models can leave a Django project with “ghost tables”, which were created for a model that was removed without any trace in the migration history. Thankfully, by using some Django internals, you can find such tables.
Use the database introspection methods table_names() to list all tables and django_table_names() to list tables associated with models. By casting these to sets, you can subtract the latter from the former to find tables not associated with a model:
In [1]: from django.db import connection
In [2]: table_names = set(connection.introspection.table_names())
In [3]: django_table_names = set(connection.introspection.django_table_names())
In [4]: table_names - django_table_names - {"django_migrations"}
Out[4]:
{'sweetshop_humbug',
'sweetshop_jellybean',
'sweetshop_marshmallow'}
Note the django_migrations table needs excluding. This is Django’s internal table for tracking migrations, which has no associated (permanent) model.
From here, you’ll want to make a judgement call on what to do with the tables. Perhaps some should have models created whilst others can be removed.
To generate a model for a ghost table, use the inspectdb management command:
$ ./manage.py inspectdb sweetshop_humbug
# This is an auto-generated Django model module.
# ...
from django.db import models
class SweetshopHumbug(models.Model):
id = models.BigAutoField(primary_key=True)
...
If a ghost table has no useful data or references in migrations, consider dropping it directly with SQL, rather than adding a migration. Make sure you have a backup, just in case! You can drop using dbshell. For example, using PostgreSQL:
$ ./manage.py dbshell
psql (...)
Type "help" for help.
candy=# DROP TABLE sweetshop_humbug;
DROP TABLE
😸😸😸 Check out my new book on using GitHub effectively, Boost Your GitHub DX! 😸😸😸
One summary email a week, no spam, I pinky promise.
Related posts:
- Django: Clean up unused code with Vulture
- Django: hoist repeated decorator definitions
- Django: avoid “useless use of
.all()”
Tags: django