The django.db.utils.OperationalError: (1060, "Duplicate column name '...'") error means Django’s migration system tried to add a column to a database table that already contains a column with that exact name. This usually happens when a migration is run multiple times, or when the database schema is out of sync with Django’s migration history.
Here are the most common reasons this happens and how to fix them:
1. You’ve manually applied a migration or modified the database directly.
- Diagnosis: Check your database schema directly (e.g., using
psqlormysqlclient, or a GUI tool like pgAdmin/DBeaver). See if the column in question actually exists in the table. Also, look at your Djangodjango_migrationstable. Does the migration that should have created this column show as applied? If it does, and the column is missing, you might have a desync. If the column is present, but the migration isn’t marked as applied, that’s a classic cause. - Fix (if column exists, migration not applied): You can manually tell Django that the migration is already done. Find the migration file that should have created the column (e.g.,
0005_add_my_field.py). Then, run:
For example, if the app ispython manage.py migrate --fake <app_name> <migration_name>myappand the migration is0005_add_my_field, you’d run:
This marks the migration as applied in thepython manage.py migrate --fake myapp 0005_add_my_fielddjango_migrationstable without actually running the SQL, effectively syncing Django’s state with the database. - Why it works: This command updates Django’s internal record of applied migrations to match the reality of the database schema, preventing Django from trying to re-apply the same change.
2. You’ve accidentally run migrate twice in quick succession, or a previous migration failed midway.
- Diagnosis: Similar to the above, check if the column exists in the database. If it does, and you know you ran
migrateand it failed, or you ran it twice, this is likely the culprit. Look at thedjango_migrationstable to see if the problematic migration is marked as applied. - Fix: If the column exists and the migration is marked as applied, you’re likely good to go. If the column exists but the migration is not marked as applied, use the
--fakecommand from point 1. If the column doesn’t exist and the migration is marked as applied, this is a trickier desync. You might need to manually create the column (if it’s safe to do so without data loss) and then use--faketo mark the migration as applied. - Why it works: The
--fakeflag is the key to re-aligning Django’s migration state with the actual database schema when an operation has already occurred but wasn’t recorded correctly.
3. You’ve reset your database or used a backup that doesn’t match your migration history.
- Diagnosis: If you’ve dropped and recreated your database, or restored from a backup, your
django_migrationstable might be empty or incomplete, while your database tables might have some schema elements from previous states. Check the database schema for the column and checkdjango_migrationsfor the relevant migration’s status. - Fix: The safest approach here is often to reset your migrations and reapply them carefully.
- Delete all migration files in your app(s) except
__init__.py. - Clear the
django_migrationstable in your database (e.g.,DELETE FROM django_migrations;). Be extremely careful with this step, especially in production. - Run
python manage.py makemigrationsto regenerate all migration files. - Run
python manage.py migrateto reapply all migrations from scratch.
- Delete all migration files in your app(s) except
- Why it works: This process reconstructs Django’s migration history and applies it cleanly to the database, ensuring everything is in sync from a known good state.
4. Multiple developers working on the same project with conflicting migration files.
- Diagnosis: If you pull code from version control and a migration file for a column already exists in the database (perhaps created by another developer’s earlier, un-merged migration), you’ll hit this. Check the database schema and the migration files in your project.
- Fix:
- Identify the migration that’s trying to add the duplicate column.
- Check if that column already exists in the database.
- If it exists, and the migration is not yet applied, use
python manage.py migrate --fake <app_name> <migration_name>. - If it exists, and the migration is already applied (and this is a new error), there’s a deeper desync. You might need to revert the problematic migration, ensure the column exists, and then re-apply. Or, if the migration is genuinely redundant, you might be able to mark it as faked.
- If the migration file is a duplicate or conflicts with another, you might need to coordinate with the other developer to decide which migration to keep and ensure only one is applied. You might need to delete one of the conflicting migration files (after ensuring the changes are captured elsewhere or already applied).
- Why it works: This requires careful coordination. The
--fakecommand is a tool to bridge gaps, but fundamentally, you need a single, agreed-upon migration history.
5. You’ve used a third-party app’s migrations and then modified their models or migrations manually.
- Diagnosis: This error can occur if you’ve edited the models or migration files of an installed third-party app (like Django REST Framework, Celery, etc.) and then tried to run your own migrations. The third-party app’s migration might try to add a column that your manual changes have already created.
- Fix: Do NOT directly edit third-party app migrations. If you need to add fields to models provided by a third-party app, create your own migration in your app that depends on the third-party app’s migration and adds the field. If you’ve already made changes:
- Review the specific migration causing the error.
- Check if the column already exists in the database.
- If it exists, and the migration is not applied, use
python manage.py migrate --fake <third_party_app> <migration_name>. - If you must alter the third-party app’s schema, it’s often cleaner to disable their migration that causes the conflict, apply your changes, and then potentially re-enable their migration (marked as fake if necessary).
- Why it works: This preserves the integrity of third-party packages. Customizations should ideally be layered on top of existing migrations, not embedded within them.
6. Inconsistent database states between development, staging, and production.
- Diagnosis: This is a meta-level issue. If you’ve developed a feature locally, created migrations, but then deployed to staging or production where the database schema is different (perhaps due to manual changes or a different migration history), you’ll see this.
- Fix: The most robust solution is to have a clear migration strategy.
- Generate migrations in your development environment.
- Test migrations thoroughly on a staging environment that closely mirrors production.
- Use database diffing tools (like
django-migration-checkeror schema comparison tools) to verify that your database schema matches your intended state before deploying. - If a desync is found, use the
--fakecommand or a full migration reset as described in previous points, depending on the severity and origin of the desync.
- Why it works: Proactive checking and consistent application of migrations across environments prevents unexpected schema conflicts during deployment.
After fixing the immediate "Column Already Exists" error, the next common issue you might encounter is django.db.utils.OperationalError: (1068, "Multiple primary key defined") if you’ve accidentally tried to define primary keys in multiple places.