1. ホーム
  2. python

[解決済み] SQLAlchemy: カスケード削除

2022-04-28 06:50:04

質問

SQLAlchemy のカスケードオプションについて、何か些細なことを見逃しているような気がします。 null 外部キー

ここに簡潔なテストケースを載せておきます。

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Parent(Base):
    __tablename__ = "parent"
    id = Column(Integer, primary_key = True)

class Child(Base):
    __tablename__ = "child"
    id = Column(Integer, primary_key = True)
    parentid = Column(Integer, ForeignKey(Parent.id))
    parent = relationship(Parent, cascade = "all,delete", backref = "children")

engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

session = Session()

parent = Parent()
parent.children.append(Child())
parent.children.append(Child())
parent.children.append(Child())

session.add(parent)
session.commit()

print "Before delete, children = {0}".format(session.query(Child).count())
print "Before delete, parent = {0}".format(session.query(Parent).count())

session.delete(parent)
session.commit()

print "After delete, children = {0}".format(session.query(Child).count())
print "After delete parent = {0}".format(session.query(Parent).count())

session.close()

出力します。

Before delete, children = 3
Before delete, parent = 1
After delete, children = 3
After delete parent = 0

親と子の間には、単純な一対多の関係があります。スクリプトは親を作成し、子を3つ追加し、コミットします。次に、親を削除しますが、子は残ります。子プロセスをカスケード削除するにはどうすればよいでしょうか?

どのように解決するのですか?

問題は、sqlalchemyが Child は親として定義されているからです (もちろん、あなたが "Child" と呼んだことは気にしません)。

もし、リレーションシップを Parent クラスの代わりに、それが動作します。

children = relationship("Child", cascade="all,delete", backref="parent")

(注 "Child" を文字列で指定します。これは、宣言的なスタイルを使用する際に、まだ定義されていないクラスを参照できるようにするためです)

を追加することができます。 delete-orphan と同様に ( delete は、親が削除されたときに子も削除されるようにします。 delete-orphan は、親が削除されなくても、親から "remove"された子も削除します)。

EDIT: 今知ったのですが、もし 本当に の関係を定義したい。 Child クラスを定義することは可能ですが、カスケードの バックリファレンス (のように、(明示的にバックリファレンスを作成することで、)このようになります。

parent = relationship(Parent, backref=backref("children", cascade="all,delete"))

(を意味する from sqlalchemy.orm import backref )