2012-08-07 13 views
7

これは問題ではありません。理解したいだけです。次のコードを考慮:リレーションシップによる削除動作

from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy import * 
from sqlalchemy.orm import sessionmaker, relationship 
Base = declarative_base() 

class AB(Base): 
    __tablename__= 'ab' 
    id_a = Column(Integer, ForeignKey('a.id', ondelete='CASCADE'), primary_key=True) 
    id_b = Column(Integer, ForeignKey('b.id', ondelete='CASCADE'), primary_key=True) 
    rel = Column(Unicode) 

class A(Base): 
    __tablename__ = 'a' 
    id = Column(Integer, primary_key=True) 

class B(Base): 
    __tablename__ = 'b' 
    id = Column(Integer, primary_key=True) 
    #1: doesn’t work try to set id_b to null 
    rel_a = relationship('AB') 
    # Works, but cascade='all' seems uneeded to me 
    rel_a = relationship('AB', cascade='all') 
    # Works 
    rel_a = relationship('AB', passive_deletes=True) 

engine = create_engine('sqlite://', echo=True) 

import logging 
logger = logging.getLogger('sqlalchemy.engine.base.Engine') 
logger.setLevel(logging.DEBUG) 
handler = logger.handlers[0] 
handler.setLevel(logging.DEBUG) 
handler.setFormatter(logging.Formatter('%(levelname)s %(message)s', '')) 

Base.metadata.create_all(engine) 

sess = sessionmaker(engine)() 

a1 = A() 
b1 = B() 
ab = AB() 

sess.add_all([a1,b1]) 
sess.flush() 

ab.id_a = a1.id 
ab.id_b = b1.id 
ab.rel = u'truite' 
sess.add(ab) 
sess.flush() 
sess.delete(b1) 
sess.flush() 

私はBから関連レコードが削除されたときABテーブルからレコードを削除することにしたいです。 は、私は(Bテーブルで確認してください)関係の3種類を試してみました:

  • 1:(:依存関係のルールのブランクアウト主キー列インスタンスの「ab.id_b」「」にしようとしたAssertionErrorが)が動作しません一方、データベース内で直接削除しようとすると、制約が正しく使用され、ABからのレコードが削除されます。

  • 2:作品、DBの制約は、作業を行う:作品発生したデータベースは、(あなたは、出力の差分を確認することができます)

  • 3と同一であるため、これが必要な理由、私は得ることはありません。 (2)が必要な理由ondelete='cascade'がすでに設定、およびDBが同一で生成されるので、残して

(3)離れて、私は、得ることはありません。私の推測は(1)となりますが、SQLAlchemyは正しい動作をするのに十分な情報を持っています。

何か不足していますか?ありがとう。

+1

ありがとうございます。本当に役に立ちました。 – clime

答えて

10

cascaderelationshipは、Session.deleteなどの操作のカスケードをSessionに設定します。これは、データベース自体の外部キー制約にある可能性のあるON X CASCADEディレクティブとは独立しています。 cascade='all'を持つあなたの場合

は、SQLAlchemyのは、カスケード接続するよう指示 Session.delete子オブジェクトの親オブジェクト( AB)から(他の操作の中で)。それがなければ、デフォルトの動作モードは、NULLを外部キー列に入れ、参照されるオブジェクトをそのままにします。

一方、passive_deletes=Trueは、ON DELETE CASCADEディレクティブを使用して、削除されたオブジェクトをクリーンアップするためにデータベースに依存するようSQLAlchemyに指示します。これにより、relationship(cascade=...)の場合のように、SQLAlchemyがクエリDELETEを単独で発行することができなくなります。

+0

これはdocよりもはっきりしています。ありがとう:) – tonio

+4

これはあなたが読んだドキュメントセクションですか? http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#cascades私は何年も何度もそのセクションを改訂しましたが、それ以上のものは必要ですか?もっと少なく ?何があなたを捨てたの? – zzzeek