operationalerrorにどハマりした件について
どうしてこうなったのか
初心者である僕は一生懸命以下2つのコマンドをポンポン叩いていました。
python manage.py makemigrations
python manage.py migrate
すると、どこかでモデル修正を間違えてしまいoperationalerror
に遭遇してしまいました。
makemigrations
は通るのにmigrate
でエラーになって通らない!!
もう冷や汗ダラダラ最悪😭って感じでした。とほほ
そもそもoperationalerrorとは?
モデルを作成・編集したのに、変更した内容をデータベースに反映していないよ!というエラーです。
このエラーが出てきたらまずはpython manage.py migrate
を実行していないことを疑ってもいいかもしれませんね。
ですが、この記事を見ている方は恐らく私と同じpython manage.py makemigrations
は通るのにpython manage.py migrate
が通らない方でしょう。
解決方法
Step1 migrationの履歴を見てみよう
(venv) % python manage.py showmigrations
admin
[X] 0001_initial
[X] 0002_logentry_remove_auto_add
[X] 0003_logentry_add_action_flag_choices
auth
[X] 0001_initial
[X] 0002_alter_permission_name_max_length
blog
[X] 0001_initial
.
.
.
[ ] 0017_notification_created_at
ここでblog
の0017_notification_created_at
に「X」がついていないことが判明しました。
※ Xが付いていない = migrateしてないよ!とうい意味です。
これが原因でmigrate
が通らないことがわかりました。
Step2 migrationsファイルを探す
例えばですが、こんなファイル構造だったとします。
project
├── config
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py # 重要
├── blog
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations ここの中にあるmigrationsファイルを探します。
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py
さっきの「X」がついていない箇所が「blog」でしたね。
なので私は blog の migrations の中から特定のファイルを探します。
そして無事0017_notification_created_at
ファイルを見つけました!!
Step3 見つけたmigrationsファイルを削除
あとは簡単です。
ファイルを削除するだけです。
この時に間違えて別のファイルを削除しないように気をつけてください。
Step4 データベースに反映させる
ここまできたらいつものmakemigrationsとmigrateをするだけです。
python manage.py makemigrations
python manage.py migrate
その際に以下のような質問を投げられるかもしれません
It is impossible to add the field 'created_at (カラム名)' with 'auto_now_add=True (ここの値をデフォルトで値を設定しないとデータベースに反映できない)' to notification without providing a default. This is because the database needs something to populate existing rows.
1) Provide a one-off default now which will be set on all existing rowsc
2) Quit and manually define a default value in models.py.
これは1を選択すると、自動でデフォルト値を決めることになるのでその場で質問形式でデフォルト値を決めることができます。
2を選択すると手動でデフォルト値または、データベースに必須ではないことを教える必要があります。
こんな感じでしょうか
※これはあくまで例です。
defaultを追加する場合
title = models.CharField(verbose_name='タイトル', max_length=30, default='タイトルです。')
データベースに保存することを必須にしない場合
title = models.CharField(verbose_name='タイトル', max_length=30, null=False)
これでOKです。
最後に
エラー解決できましたでしょうか?
私はこれを知るまではいちいちデータベースの中身を全て消して空っぽにしてから再度migrateしてました。笑
migrationsファイルを削除するだけで解決できるとは。。。いい時代になったものだ。