データベースのON UPDATE と ON DELETEの機能と、ORMレベルでのdelete機能がある。
ORM 側に囲み記事がある通り、この二つは機能的に重複していて、挙動に注意が必要になる。超意訳してみる。
まずデータベースでの ON DELETE
は many-to-one の many 側に記述するが、ORM では逆転して one-to-many 側に記述する。両方同時に書くと次のようになる。
from sqlalchemy import event, ForeignKey
from sqlalchemy.orm import relationship, backref
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class A(db.Model):
__tablename__ = "a"
k = db.Column(db.String, primary_key=True)
bs = relationship("B", backref="a", cascade="all") # one 側であるAに記述
class B(db.Model):
__tablename__ = "b"
k = db.Column(db.String, primary_key=True)
a_id = db.Column(db.String, ForeignKey("a.k", ondelete="CASCADE")) # many 側であるBに記述
一般的に ON DELETE
は「親が消されないようにする」ために使われる。同様の挙動を ORM で実現したい場合は次の 2 通りの方法がある。前提知識として、ORM のデフォルトの挙動では、外部キーを NULL に更新する。1.) 外部キーを保持するカラムに NOT NULL
制約を付けて、ORM のデフォルトの挙動を阻害する。2.) cascade="all" に passive_deletes
フラグをつけると、外部キーを NULL に設定することなく親が消される。この場合データベースレベルでの何らかの仕組みを併用する。
データベースレベルでの ON DELETE
は効率が良い。一方で ORM ではひとつずつ DELETE
が実行される。
passive_deletes
をうまく使え。
ON DELETE
は many 側でのみ動作するように、SQLAlchemy でも逆向きに使って many 側で設定すること自体はできる。実用的には one-to-one の場合で、この場合は single_parent
フラグを設定しよう。