13

コード例を次に示します。

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()

次に、グループを削除しようとします

session.delete(g)
session.commit()

このエラーの何らかの形式が表示されます。

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

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

どんなアドバイスでも大歓迎です。

4

2 に答える 2

16

Group.users と Group.users_dynamic の両方の関係は、グループがUser()参照するオブジェクトを管理できることに加えて、グループが削除されているという事実を調整しようとしています。関連テーブルの行が既に削除されているため、1 つの関係は成功しますが、2 つ目の関係は失敗します。最も簡単な解決策は、同一のリレーションシップの 1 つを除くすべてをビューのみとしてマークすることです。

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')

両方のリレーションシップである程度のミューテーションを処理したい場合は、SQLAlchemy が 2 つのリレーションシップの変更を同時に調整する方法を知らないため、慎重に行う必要があります。両方の関係で同等の突然変異を行うと、(二重挿入などのように)発生します。「削除」の問題を単独で処理するには、Group.users_dynamic を passive_deletes=True に設定することもできます。

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')
于 2013-06-21T19:15:30.407 に答える