Django JSONStore

Blog · Migrations

Why Django migrate says the table already exists

Django keeps two records of the schema: the database itself, and the rows in django_migrations. This error means the two disagree. The table is present, and the row that records its creation is absent.

django.db.utils.OperationalError: table "myapp_invoice" already exists
# PostgreSQL: relation "myapp_invoice" already exists
# Oracle:     ORA-00955: name is already used by an existing object

Four causes produce this state. Find the cause before the repair, because the repair for one cause damages another.

Compare the two records

Read the applied rows, then read the real tables. The difference names the cause.

manage.py showmigrations myapp

manage.py dbshell
> SELECT app, name FROM django_migrations WHERE app = 'myapp' ORDER BY id;

If showmigrations shows [ ] for a migration whose table is in the database, the records are behind the schema. This is the normal case, and --fake-initial repairs it.

manage.py migrate myapp --fake-initial

--fake-initial marks an initial migration as applied when its tables are already present, and it applies each later migration in the usual way. It checks the table names, and it does not compare the columns.

--fake-initial checks the table names only, so a column difference stays hidden. The command reports success, and a later migration fails on a column that is absent. After the repair, run manage.py makemigrations --check --dry-run. An exit code of 1 means the models and the schema still disagree, and the difference needs a real migration.

When the schema is ahead by one column

For a single object, mark the one migration as applied instead of the whole app.

manage.py migrate myapp 0004 --fake

When the table is not wanted

If the table belongs to a deleted model, or to an experiment, drop it and let the migration build it again. This destroys the rows in the table.

manage.py dbshell
> DROP TABLE myapp_invoice;          # the data goes with it

manage.py migrate myapp

Two apps with the same db_table need a different repair: change one of the two Meta.db_table values, and write a migration for the rename. A drop deletes the data of the other app.