できない.dev

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 のもので、他のデータベースでは表現が変わるが原因は同じだ。

よくある原因

  1. マイグレーションを作っていない: 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.」と警告が出る。
  2. INSTALLED_APPS に登録していない: 登録していないアプリのモデルは Django から見えないので、makemigrations は No changes detected を返して何も作らない。
  3. migrate を実行していない・対象のデータベースが違う: マイグレーションファイルがあっても、適用するまでテーブルは無い。
    別のコンテナで実行した、環境変数で DATABASES の接続先が変わっている、といった場合は適用先が食い違う。
  4. フィールドの追加をマイグレーションしていない: この場合は no such column: blog_post.body になるが、原因と直し方は同じだ。
  5. マイグレーションファイルを共有していない: マイグレーションファイルはアプリのコードと一緒に配布する前提のものだ。.gitignore で除外すると、クローンした環境ではテーブルが作られない。

解決策

1. マイグレーションを作って適用する

python manage.py makemigrations blog
python manage.py migrate

makemigrations が 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 blog
blog
 [ ] 0001_initial

[ ] なら migrate を、(no migrations) なら手順 1 を実行する。
Docker Compose では、アプリが接続するコンテナで実行する。

docker compose exec web python manage.py migrate

migrate --fake は SQL を実行せずに適用済みの印だけを付けるので、この問題の解決には使わない。

4. マイグレーションファイルをコミットする

makemigrations が作ったファイルは、モデルのコードと同じコミットに含める。

git add blog/migrations/
git commit -m "blog: Post モデルを追加"

公式ドキュメントは、マイグレーションを開発環境で一度作り、同じものを他の環境や本番で適用する流れを示している。
クローンした環境では共有されたファイルに対して migrate を実行する。

この記事は役立ちましたか?