Fix: django.db.utils.OperationalError: no such table (SQLite / PostgreSQL / MySQL)
The Error
You run your Django application or execute a management command, and you get:
django.db.utils.OperationalError: no such table: myapp_mymodelThis is the SQLite variant. If you’re using PostgreSQL, the error looks like:
django.db.utils.ProgrammingError: relation "myapp_mymodel" does not existWith MySQL, you’ll see:
django.db.utils.OperationalError: (1146, "Table 'mydb.myapp_mymodel' doesn't exist")Or during test runs:
django.db.utils.OperationalError: no such table: django_sessiondjango.db.utils.OperationalError: no such table: auth_userAll of these mean the same thing: Django is trying to query a database table that hasn’t been created yet.
Why This Happens
Django uses a migration system to keep your database schema in sync with your Python model definitions. When you define a model in models.py, Django doesn’t immediately create the corresponding table. Instead, you generate a migration file (a Python script describing the schema change) and then apply it to the database.
The process works in two steps:
python manage.py makemigrations— Inspects your models and creates migration files in themigrations/directory of each app.python manage.py migrate— Reads those migration files and executes the SQL statements to create or alter tables in the database.
If either step is skipped, incomplete, or broken, the table won’t exist when Django tries to access it. The “no such table” error is Django telling you it tried to run a SQL query against a table that the database doesn’t know about.
This can happen for many reasons: you forgot to run migrations, migration files were deleted, your settings.py points to the wrong database, your Docker container lost its data, or your migration history is out of sync. The fixes below cover each scenario.
Fix 1: Run Migrations
The most common cause. You have migration files but haven’t applied them to the database.
python manage.py migrateThis applies all pending migrations across all installed apps. If the command succeeds, your tables are created and the error should be gone.
To see which migrations are pending without applying them:
python manage.py showmigrationsThis prints every migration for every app, with an [X] next to applied ones and [ ] next to unapplied ones. If you see unapplied migrations for the app mentioned in your error, migrate will fix it.
If you want to apply migrations for a specific app only:
python manage.py migrate myappAfter running migrations, restart your Django development server to make sure the new schema is picked up.
Fix 2: Run makemigrations First
If migrate says “No migrations to apply” but the table still doesn’t exist, you probably never generated the migration files. This happens when you create a new model but forget to run makemigrations.
python manage.py makemigrationsThen apply them:
python manage.py migrateIf makemigrations says “No changes detected”, Django isn’t seeing your model. Check these:
- Is the app in
INSTALLED_APPS? Opensettings.pyand make sure your app is listed:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp', # <-- your app must be here
]If your app uses an AppConfig, you might need the full dotted path:
INSTALLED_APPS = [
# ...
'myapp.apps.MyappConfig',
]Does your
models.pyactually define the model? Make sure the model class inherits fromdjango.db.models.Modeland is not inside a conditional block or commented out. This is similar to how Python’s “no module named” errors can stem from incorrect import paths or missing packages — the framework simply can’t find what you’re pointing it at.Did you specify the app label? If your app has an unusual structure, try passing the app name explicitly:
python manage.py makemigrations myappFix 3: Restore Missing Migration Files
Migration files can go missing in several ways:
- Someone deleted the
migrations/directory thinking it was auto-generated cache. - The
.gitignorefile excludes migration files. - A merge conflict deleted migration files.
Check your .gitignore:
cat .gitignore | grep migrationIf you see */migrations/ or *.py patterns inside a migrations directory, migration files are being excluded from version control. Migration files should be committed to your repository. Remove any .gitignore rules that exclude them.
If migration files are lost, you can regenerate them:
python manage.py makemigrations myappBut there’s a catch: if the database already has some tables from old migrations, the new migration files won’t match the migration history recorded in the django_migrations table. You’ll get errors like:
django.db.migrations.exceptions.InconsistentMigrationHistoryTo fix this, you can fake the initial migration (telling Django to mark it as applied without actually running the SQL):
python manage.py migrate myapp --fake-initialOr if you’re starting fresh, delete the database and run migrate from scratch. With SQLite, that means deleting the db.sqlite3 file. With PostgreSQL or MySQL, drop and recreate the database. See Fix: PostgreSQL Connection Refused if you run into connection issues while doing this.
Fix 4: Check Your Database Configuration in settings.py
Django might be connecting to a different database than the one you ran migrations against. This is surprisingly common when switching between development environments or when environment variables aren’t set.
Open settings.py and check the DATABASES setting:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}Common misconfigurations:
- The
NAMEpath is wrong. IfBASE_DIRis set incorrectly or you’re running the app from a different working directory, Django creates a new empty SQLite file somewhere unexpected. Search your project fordb.sqlite3files:
find . -name "db.sqlite3"If you find more than one, you’ve been migrating one database but running the app against another.
- Environment variables aren’t set. If your database config reads from environment variables:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'mydb'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD', ''),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', '5432'),
}
}Make sure those environment variables are actually set in your shell. An unset DB_NAME falls back to the default, which may point to a different database than you expect. If you’re encountering issues connecting to MySQL after fixing the table name, see Fix: MySQL Access Denied for User for authentication troubleshooting.
- You switched from SQLite to PostgreSQL (or vice versa) without migrating the new database. Changing the
ENGINEdoesn’t transfer your data or schema. You need to runmigrateagain on the new database.
Fix 5: Fix Test Database Issues
If the error only occurs during tests, Django’s test runner creates a separate test database. The test database is created fresh for each test run, and migrations are applied automatically. But things can go wrong.
The test database name is auto-generated. By default, Django prefixes your database name with test_. If your database is named mydb, the test database is test_mydb. Make sure the database user has permission to create databases.
For PostgreSQL:
ALTER USER myuser CREATEDB;You’re using --keepdb with stale schema. The --keepdb flag reuses the test database between runs for speed. But if you’ve added new migrations, the existing test database won’t have them:
# Drop and recreate the test database
python manage.py test
# Or explicitly destroy the old one
python manage.py test --keepdbIf --keepdb causes the error, drop it and run without it.
Serialized rollback issues. If you use TransactionTestCase with serialized_rollback = True, Django tries to serialize and restore the database state. Corrupted serialization can cause “no such table” errors. Delete the test database and run tests again.
Your test is running code at import time. If a module imported during test setup queries the database (for example, a model’s __init__.py runs a query at import), it can fail before the test database is ready. Move database-dependent code out of module-level execution and into functions or methods.
Fix 6: Handle Multiple Databases
If your Django project uses multiple databases with a database router, migrations might not be applied to the correct database.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
},
'analytics': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'analytics_db',
'USER': 'postgres',
'HOST': 'localhost',
}
}Run migrations for each database explicitly:
python manage.py migrate --database=default
python manage.py migrate --database=analyticsIf you have a database router that controls which models go to which database, make sure the router’s allow_migrate() method returns True for the relevant app and database combination:
class AnalyticsRouter:
def allow_migrate(self, db, app_label, model_name=None, **hints):
if app_label == 'analytics':
return db == 'analytics'
return db == 'default'A misconfigured router can silently prevent migrations from being applied to a specific database, leaving tables missing.
Fix 7: Resolve Migration Conflicts
When multiple developers create migrations for the same app on different branches, merging creates a conflict: two migrations share the same parent. Django raises:
CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graphIf you ignore this or resolve it incorrectly, migrations can be applied in the wrong order or skipped entirely, leaving tables uncreated.
Fix the conflict with Django’s built-in merge command:
python manage.py makemigrations --mergeThis creates a new migration file that lists both conflicting migrations as dependencies, allowing them to be applied in sequence. Review the generated merge migration, then apply it:
python manage.py migrateIf the conflict is too tangled, a more drastic approach is to squash migrations. But be careful — squashing is only safe if all team members have applied all existing migrations first:
python manage.py squashmigrations myapp 0001 0015After squashing, test that migrate works on a fresh database before committing. Migration issues can be as frustrating as Python IndentationError — they’re easy to cause and sometimes tricky to track down.
Fix 8: Fix a Corrupted SQLite Database File
SQLite databases are single files, and they can be corrupted by:
- The process being killed while writing (e.g.,
Ctrl+Cduring a migration). - Running out of disk space mid-write.
- Multiple processes writing simultaneously without proper locking.
- Copying the file while it’s being written to.
Check if the file is corrupted:
sqlite3 db.sqlite3 "PRAGMA integrity_check;"If it returns anything other than ok, the file is corrupted.
To recover, you have a few options:
Option 1: Delete and recreate. If this is a development database and you don’t need the data:
rm db.sqlite3
python manage.py migrateOption 2: Dump and restore. If the database is partially readable:
sqlite3 db.sqlite3 ".dump" > backup.sql
rm db.sqlite3
sqlite3 db.sqlite3 < backup.sql
python manage.py migrateOption 3: Use a backup. If you have a recent backup, restore it and run any new migrations:
cp db.sqlite3.backup db.sqlite3
python manage.py migrateFor production applications, SQLite is generally not recommended. Consider switching to PostgreSQL or MySQL. If you run into dependency issues while installing the database driver (psycopg2 or mysqlclient), see Fix: pip Could Not Build Wheels for help resolving compilation errors.
Fix 9: Persist the Database in Docker
A very common scenario: migrations succeed during docker build, but the database is empty when the container starts. This happens because Docker image layers are read-only at runtime. If you run migrate in the Dockerfile, the resulting db.sqlite3 is baked into the image, but any writes at runtime go to an ephemeral container layer that’s lost when the container stops.
Wrong approach (SQLite in Docker):
# This creates the DB during build, but it resets on every container restart
RUN python manage.py migrateCorrect approach: use a volume.
# docker-compose.yml
services:
web:
build: .
volumes:
- db-data:/app/db
command: >
sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
volumes:
db-data:Make sure your settings.py points NAME to the mounted path:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': '/app/db/db.sqlite3',
}
}For PostgreSQL/MySQL in Docker, the database service needs its own volume:
services:
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: mydb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
web:
build: .
environment:
DATABASE_URL: postgresql://postgres:secret@db:5432/mydb
depends_on:
db:
condition: service_healthy
command: >
sh -c "python manage.py migrate && gunicorn myproject.wsgi:application --bind 0.0.0.0:8000"
volumes:
pgdata:Run migrations as part of the container’s startup command (or in an entrypoint script), not during the image build. The database service must be ready before migrations run — use depends_on with a health check as shown above.
If you accidentally deleted a Docker volume, the database and all its tables are gone. You’ll need to run migrate again:
docker compose down -v # WARNING: this destroys volumes
docker compose up -d
docker compose exec web python manage.py migrateFix 10: Circular Dependencies in Models
If two apps reference each other’s models via ForeignKey, Django can fail to create the migration graph in the correct order, resulting in a table not existing when a foreign key constraint tries to reference it.
For example, app_a has a ForeignKey to app_b, and app_b has a ForeignKey to app_a. The migration for app_a depends on app_b’s table existing, and vice versa.
Use string references to avoid circular imports:
# app_a/models.py
class Order(models.Model):
customer = models.ForeignKey('app_b.Customer', on_delete=models.CASCADE)# app_b/models.py
class Customer(models.Model):
last_order = models.ForeignKey('app_a.Order', on_delete=models.SET_NULL, null=True)Django handles string-based references by resolving them lazily, which avoids the import-time circular dependency. However, the migration files still need explicit dependencies entries. Django usually handles this automatically, but if it doesn’t, you can add the dependency manually in the migration file:
class Migration(migrations.Migration):
dependencies = [
('app_b', '0001_initial'),
]
# ...If the circular dependency is too deep to resolve, consider restructuring your models. Move the shared reference into a third app, or replace one of the ForeignKey fields with a GenericForeignKey, or defer one of the relationships to a later migration using SeparateDatabaseAndState.
Still Not Working?
The django_migrations table itself is missing
If someone manually dropped tables but left others, the django_migrations tracking table might be gone while other tables still exist. Recreate it:
python manage.py migrate --run-syncdbOr if that doesn’t work, create just the internal Django tables:
python manage.py migrate django.contrib.contenttypes
python manage.py migrate auth
python manage.py migrateContentType or Permission tables missing
If the error references django_content_type or auth_permission, these are Django internal tables. They’re created by the contenttypes and auth apps respectively. Make sure both are in INSTALLED_APPS (they are by default) and run:
python manage.py migrate contenttypes
python manage.py migrate auth
python manage.py migrateMigration file references a model that no longer exists
If you deleted a model from models.py but the migration file still references it, applying that migration fails. You need to create a new migration that removes the model:
python manage.py makemigrations myappDjango will detect that the model was removed and generate a DeleteModel operation. Apply it:
python manage.py migrateThird-party app tables are missing
If the error references a table from a third-party package (like django-allauth, django-rest-framework, or celery), make sure the package is installed in your virtual environment and the app is in INSTALLED_APPS. Then run migrate. If you recently installed a new package and are seeing import errors alongside the table error, check Fix: Python “No Module Named” to make sure your virtual environment is set up correctly.
The migration runs but the table still doesn’t exist
In rare cases, a migration might use RunSQL or RunPython operations that fail silently, or a custom database backend might not support certain DDL operations. Check the migration file directly:
python manage.py sqlmigrate myapp 0001This prints the SQL that Django would execute for that migration. Run that SQL manually against your database to see if there’s an error.
You’re using a read-only database replica
If your app connects to a read-only replica for queries, that replica won’t have tables created by migrate until replication catches up. Make sure migrate runs against the primary database, and give the replica time to sync.
Related: If you’re setting up a Django project with PostgreSQL and can’t connect, see Fix: PostgreSQL Connection Refused. For MySQL authentication errors, see Fix: MySQL Access Denied for User. If pip install psycopg2 or pip install mysqlclient fails during setup, see Fix: pip Could Not Build Wheels.
Related Articles
Fix: PostgreSQL ERROR: duplicate key value violates unique constraint
How to fix 'duplicate key value violates unique constraint' in PostgreSQL by resetting sequences, using upserts, fixing bulk imports, and handling concurrent inserts.
Fix: ImportError: cannot import name 'X' from partially initialized module (circular import)
How to fix Python's circular import error: ImportError cannot import name from partially initialized module. Covers lazy imports, module restructuring, TYPE_CHECKING, Django, Flask, and more.
Fix: PostgreSQL Connection Refused – Could Not Connect to Server
How to fix the PostgreSQL error 'could not connect to server: Connection refused' caused by server not running, wrong host/port, pg_hba.conf, or firewall issues.
Fix: Python IndentationError – Unexpected Indent or Expected an Indented Block
How to fix Python IndentationError including unexpected indent, expected an indented block, and unindent does not match, caused by mixed tabs and spaces or incorrect nesting.