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.

删除关系的第二个版本(在我的例子中是动态的)解决了这个问题。我什至不知道从哪里开始理解为什么会发生这种情况。在我的 SQLAlchemy 模型中,在许多情况下,我一直在使用各种关系的 2 个版本,以便在给定情况下轻松使用最合适的查询策略。这是它第一次引起意想不到的问题。

欢迎任何建议。

4

2 回答 2

16

Group.users 和 Group.users_dynamic 关系都试图协调 Group 被删除以及能够管理User()它们引用的对象的事实;一个关系成功,而第二个关系失败,因为关联表中的行已被删除。最直接的解决方案是将除了一个相同的关系之外的所有关系都标记为仅查看:

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 不知道如何同时在两个关系中的更改之间进行协调,因此这样的冲突可能会继续如果您在两个关系上进行等效突变,则会发生(如双插入等)。要自己处理“删除”问题,您还可以尝试将 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 回答
0

我只是添加另一个简单的解决方法。

您可以在删除项目本身之前删除集合:

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

或者,您也可以将其设置为空列表:

>>> group.users = []
>>> db.session.commit()
>>> db.session.delete(group)
>>> db.session.commit()
于 2017-07-29T07:50:59.083 回答