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.
- The
django_migrationsrows were deleted, or the database was restored from a dump that holds the tables and not those rows. - The initial migration file was deleted and written again, so it has a new name and no record.
- Two apps declare the same
db_table. - The table was created by hand, or by a second project on the same database.
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.