2013-06-19 2 views
7

両方レイジー負荷と同じ関係の動的なバージョンを持っていることによって生じる誤差をDELETEは、いくつかのサンプルコードです:SQLAlchemyのはここ

users_groups = Table('users_groups', Model.metadata, 
    Column('user_id', Integer, ForeignKey('users.id')), 
    Column('group_id', Integer, ForeignKey('groups.id')) 
) 

class User(Model): 
    __tablename__ = 'users' 
    id = Column(Integer, primary_key=True) 


class Group(Model): 
    __tablename__ = 'groups' 
    id = Column(Integer, primary_key=True) 

    users = relationship('User', secondary=users_groups, lazy='select', backref='groups') 
    users_dynamic = relationship('User', secondary=users_groups, lazy='dynamic') 

それでは、ここで起こるあなたがユーザーの束を追加した場合ということですそのようなグループ:

g = Group() 
g.users = [User(), User(), User()] 
session.add(g) 
session.commit() 

、その後、あなたは、いくつかのFOを取得するグループ

session.delete(g) 
session.commit() 

を削除しようとしますこのエラーのrm:

DELETE statement on table 'users_groups' expected to delete 3 row(s); Only 0 were matched. 

関係の2番目のバージョン(私の場合は動的なもの)を削除すると、この問題が修正されます。私はなぜこれが起こっているのかを理解するという点でどこから始めるべきかはわかりません。私は、状況に応じて最も適切なクエリ戦略を使いやすくするために、多くの場合、SQLAlchemyモデル全体でさまざまな関係の2つのバージョンを使用してきました。予期しない問題が発生したのは初めてです。

アドバイスをよろしくお願いいたします。

答えて

9

Group.usersとGroup.users_dynamicの両方の関係で、グループが削除されているという事実と、それが参照するUser()オブジェクトを管理できることの両方を調整しようとしています。関連テーブルの行がすでに削除されているため、1つの関係は成功し、2つ目は失敗します。あなたはまだ両方の関係が突然変異のいくつかの学位を扱う持っているしたいとしている場合、あなたはSQLAlchemyのよう慎重にこれを実行する必要があると思い

class Group(Base): 
    __tablename__ = 'groups' 
    id = Column(Integer, primary_key=True) 

    users = relationship('User', secondary=users_groups, lazy='select', backref='groups') 
    users_dynamic = relationship('User', viewonly=True, secondary=users_groups, lazy='dynamic') 

:最も簡単な解決策は、としてviewonly、同一の関係のうちの1つを除くすべてをマークすることです同時に2つの関係の変化を調整する方法を知らないので、両方の関係で等価な突然変異を作成すると、このような競合が起こり続けることがあります(二重挿入など)。ただ、それ自体で「削除」問題の世話をするために、あなたはまた、真= passive_deletesにGroup.users_dynamicを設定してみてくださいすることができます

class Group(Base): 
    __tablename__ = 'groups' 
    id = Column(Integer, primary_key=True) 

    users = relationship('User', secondary=users_groups, lazy='select', backref='groups') 
    users_dynamic = relationship('User', passive_deletes=True, secondary=users_groups, lazy='dynamic') 
+0

私はパッシブ削除フラグを追加し、正しく理解していれば:あなたはまた、空のリストとして設定することができ、また

>>> for user in group.users: group.users.remove(user) >>> db.session.delete(group) >>> db.session.commit() 

あなたは項目自体を削除する前に、コレクションを削除することができますグループが削除されたときにORMが特定のコレクションを削除しようとしないようにしますか?もしそうなら、それは最も副作用のない解決策のように思えます、ありがとう。 –

+0

もう一つの注意点として、SQLAlchemyは私が今までに使った中で最高のORMであり、IMOのコミュニティで最高のオープンソースのPythonライブラリの1つです。ありがとう、あなたとあなたの猫は素晴らしいです。 –

0

私はちょうど別の簡単な回避策を追加します。

>>> group.users = [] 
>>> db.session.commit() 
>>> db.session.delete(group) 
>>> db.session.commit() 
関連する問題