Django で「no such table」が出てモデルのテーブルを参照できない
OperationalError: no such table は、モデルに対応するテーブルがデータベースにまだ作られていないときに出る。makemigrations でマイグレーションを作り migrate で適用する 2 段階のどちらかが抜けていることがほとんどだ。
公開:
要約
Django の ORM は、モデルを定義しただけではテーブルを作らない。
変更をファイルに書き出す makemigrations と、それを適用する migrate のどちらかが抜けると、クエリの実行時に次のエラーになる。
django.db.utils.OperationalError: no such table: blog_postテーブル名は既定で アプリ名_モデル名 の小文字になる。
文言は SQLite のもので、他のデータベースでは表現が変わるが原因は同じだ。
よくある原因
- マイグレーションを作っていない:
migrateだけを実行すると、admin や auth など Django 同梱アプリのテーブルは作られるが、自分のアプリのテーブルは作られない。
適用するマイグレーションが残っていない状態でmigrateを実行すると「Your models in app(s): 'blog' have changes that are not yet reflected in a migration, and so won't be applied.」と警告が出る。 INSTALLED_APPSに登録していない: 登録していないアプリのモデルは Django から見えないので、makemigrationsはNo changes detectedを返して何も作らない。migrateを実行していない・対象のデータベースが違う: マイグレーションファイルがあっても、適用するまでテーブルは無い。
別のコンテナで実行した、環境変数でDATABASESの接続先が変わっている、といった場合は適用先が食い違う。- フィールドの追加をマイグレーションしていない: この場合は
no such column: blog_post.bodyになるが、原因と直し方は同じだ。 - マイグレーションファイルを共有していない: マイグレーションファイルはアプリのコードと一緒に配布する前提のものだ。
.gitignoreで除外すると、クローンした環境ではテーブルが作られない。
解決策
1. マイグレーションを作って適用する
python manage.py makemigrations blog
python manage.py migratemakemigrations が blog/migrations/0001_initial.py を作り、migrate が適用すればテーブルができる。
モデルを変更するたびに、この 2 つをセットで実行する。
フィールドを足しただけのときも省略しない。
2. INSTALLED_APPS に追加する
No changes detected と出たら、アプリが登録されているかを確認する。
# settings.py
INSTALLED_APPS = [
"blog.apps.BlogConfig",
"django.contrib.admin",
"django.contrib.auth",
# ...
]登録を忘れたままモデルを import すると、Model class blog.models.Post doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS. という RuntimeError になることもある。
3. 適用状況を確認する
showmigrations は、適用済みのマイグレーションに [X] を付けて一覧表示する。
python manage.py showmigrations blogblog
[ ] 0001_initial[ ] なら migrate を、(no migrations) なら手順 1 を実行する。
Docker Compose では、アプリが接続するコンテナで実行する。
docker compose exec web python manage.py migratemigrate --fake は SQL を実行せずに適用済みの印だけを付けるので、この問題の解決には使わない。
4. マイグレーションファイルをコミットする
makemigrations が作ったファイルは、モデルのコードと同じコミットに含める。
git add blog/migrations/
git commit -m "blog: Post モデルを追加"公式ドキュメントは、マイグレーションを開発環境で一度作り、同じものを他の環境や本番で適用する流れを示している。
クローンした環境では共有されたファイルに対して migrate を実行する。