はじめに
pythonのORMマッパーであるpeeweeでUserテーブルの行を削除するAPIを書いたところ以下のようなエラーが発生しました.
peewee.IntegrityError: (1451, 'Cannot delete or update a parent row: a foreign key constraint fails (`atnow_database`.`task`, CONSTRAINT `task_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`))')
原因
今回使用したpeeweeのORMモデルは以下のようになっていました.
import peewee
from code.models.base import Base
class User(Base):
username = peewee.CharField(unique=True, index=True)
is_active = peewee.BooleanField(default=True)
hashed_user_token = peewee.CharField()
from code.models.base import Base
from code.models.user import User
class Task(Base):
name = peewee.CharField(max_length=30, index=True)
description = peewee.CharField(max_length=300, default='')
# 外部キー
user = peewee.ForeignKeyField(User, backref='tasks')
このようなモデル設計において,Userの行を削除しようとしていました.
ここで,Task側のテーブルは外部キーとしてUserを持っています.
また,それをUser側も知っており外部参照されていることを知っています.
よって,何も指定しないまま書くと自動的に外部キー制約がSQLのテーブルのスキーマに追加されます.
そのため,Userの行だけを削除しようとすると,関連ついているTaskたちが取り残されてしまうので,それを防ぐために削除を許さず1451エラーが出ていました.
Task側に立って考えてみると,参照先のUserが勝手に消えていたら困ってしまいますね..
対応策
削除されたときのアクションを文字列で指定できます.
CASCADE
を用いると,Userを消すときに関連づいているTaskも自動で消せるため,エラーは起こりません.
class Task(Base):
name = peewee.CharField(max_length=30, index=True)
description = peewee.CharField(max_length=300, default='')
# 外部キー
user = peewee.ForeignKeyField(User, backref='tasks', on_delete='CASCADE')