LoginSignup
7
4

More than 5 years have passed since last update.

SQLAlchemy ORM での foreign key 削除

Last updated at Posted at 2018-08-15

データベースの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 フラグを設定しよう。

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4