【Django】 .db.utils.OperationalError: (1091, "Ca n't DROP'フィールド名'; ...)の解消方法


投稿日 2020年8月15日 >> 更新日 2023年3月2日

今回は、Djangoでマイグレーションを実行しときに引き起こした「django.db.utils.OperationalError: (1091, "Ca n't DROP'フィールド名'; check that column / key exists")」について説明していきたいと思います。

上記のようなエラーを出してしまった背景は、Djangoのモデルに変更を加え、最終的に「migrate」コマンドを実行した際に起こりました。

Djangoのモデルフィールドなどに変更を加える際は、毎回データベースに反映させなければいけないので、「makemigrations」に引き続き「migrate」を実行します。

恐らく1つのWebサイトを育てている人にとっては、過去に上記の工程をうっかり忘れてしまっていたり、もしくわ失敗などを繰り返してマイグレーションファイル(移行ファイル)を削除したりして、マイグレーションファイルのプロセスが飛び飛び、もしくわマッチしなくなっていたりします。

そんな時に出現される可能性のある「django.db.utils.OperationalError:」をすぐに解消できるように確認すべきポイントを押さえて見ていきます。

実行環境&使用ライブラリ

実行環境
Windows Subsystem for Linux
Python 3.6.9
pip 9.0.1
使用ライブラリ ライセンス
Django==2.2.5 BSD

エラー内容

この「django.db.utils.OperationalError: (1091, "Ca n't DROP'フィールド名'; check that column / key exists")」エラーをGoogle翻訳に充てると、「削除できません 'フィールド名'; 列/キーが存在することを確認してください」となります。

「'フィールド名'」という部分にモデルで定義されているフィールド名が入ります。

Djangoは、そのフィールドがあるという前提で「makemigrations」時に移行ファイルを作成しているので、「migrate」を実行するときは移行ファイルに従って処理を進めて行きます。

# app/migrations

app
  |--__init__.py
  |--__pycache__
  |--migrations
           |--__pycache__
           |--__init__.py
           |--0001_initial.py   # 移行ファイル達
           |--0002...py
           |--0003...py

「migrate」コマンドでDjangoが処理を進めて行った結果、「移行ファイル(マイグレーションファイル)上ではあるはずのフィールドが無いので削除を実行できない」という事に陥っているという事です。

アプリケーションディレクトリ内の「migrations」ディレクトリを確認すると、恐らく問題のフィールドを削除した形跡が残っていないと思われます。

問題のフィールドが削除されているならば、以下のようなファイルが作成されているはずです。

# app/migrations

app
  |--__init__.py
  |--__pycache__
  |--migrations
           |--__pycache__
           |--__init__.py
           |--0001_initial.py
           |--0002...py
           |--0003...py
           |--0004_モデル名_フィールド名.py  # フィールドの作成
           |--0005_remove_モデル名_フィールド名.py  # フィールドの削除
           |--0006_....py

問題のフィールドが見当たらないといった場合は、最新の移行ファイルの中身を確認してみると良いです。

# app/migrations/0011_auto_......py

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('アプリ名', '0010_auto_......'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='モデル名',
            name='問題のフィールド',
        ),
        migrations.AlterField(
            model_name='モデル名',
            name='created_at',
            field=models.DateField(),
        ),
    .....

    ]

直近で変更を加えようとしている「operations」リスト内では、問題のフィールドの削除と、「created_at」フィールドに対する変更です。

私の場合ですと、直近で変更を加えたのは「created_at」フィールドだけなので、有るはずのない問題のフィールドをDjangoは削除しようとしています。

これにより「django.db.utils.OperationalError: (1091, "Ca n't DROP'フィールド名'; check that column / key exists")」といった事態に陥っていました。

解決方法

データベースの中に、問題のフィールドが存在していないか確認してみます。

# 実行

$ python3 manage.py dbshell

MySQLの例

# テーブルの確認
mysql> show tables;
+----------------------------+
| Tables_in_dbname            |
+----------------------------+
|....
| アプリ_モデル                 |
|....
+----------------------------+
mysql>
# フィールド(カラム)の確認
mysql> show columns from blogs_blog;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+

SQLiteの例

# テーブルの確認
sqlite> .table
.....                    アプリ_モデル
.....                    ......
.....   
sqlite>
# フィールド(カラム)の確認
sqlite> .schema アプリ_モデル
CREATE TABLE IF NOT EXISTS "アプリ_モデル" ("フィールド".....);

問題のフィールドが存在していた場合は、他のエラーに繋がる可能性があるので削除しておくのが賢明です。

データベースフィールドの削除に関してはこちらの記事で詳しく説明しています。

問題のフィールドが存在していないことが確認できたら、マイグレーションファイル(移行ファイル)を削除・もしくわ移動していきます。

以下のような構造の移行ファイルであったとしたら、問題のフィールドに関するファイルを削除・もしくわ移動してしまいます。

※心配な方は削除せず、別のディレクトリへ移動させましょう(自己責任でお願いします)。

# app/migrations

app
  |--__init__.py
  |--__pycache__
  |--migrations
           |--__pycache__
           |--__init__.py
           |--0001_initial.py
           |--0002...py
           |--0003...py
           |--0004_モデル名_フィールド名.py  # 問題のフィールドが作成された以降を移動
           |--0005_....py  # 移動
           |--0006_....py  # 移動

ファイルの中身を良く確認し、問題のフィールドと関連のありそうなファイルを削除・もしくわ移動させていきます。

結果

# app/migrations

app
  |--__init__.py
  |--__pycache__
  |--migrations
           |--__pycache__
           |--__init__.py
           |--0001_initial.py
           |--0002...py
           |--0003...py

そして、マイグレーションコマンドを実行します。

# 実行

$ python3 manage.py makemigrations アプリ名
Migrations for 'アプリ名':
....
$ python3 manage.py migrate アプリ名
Operations to perform:
  Apply all migrations: アプリ名
Running migrations:
  Applying アプリ名.00... OK

実行して上記のようなアラートが出れば成功です。

Djangoでは非常に簡単にデータベースの構築を行うことができますが、どのようなプロセスをもって作成しているのかを押さえておくと、なんらかのトラブル時に役立ちます。

逆に失敗したからこそ学べたことが殆どだと思いますが、どんどん弄り倒していきましょう。

それでは以上となります。

最後までご覧いただきありがとうございました。