SQLAlchemy DELETE由于具有延迟加载和相同关系的动态版本而导致的错误

Pet*_*ias 9 python mysql 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')
Run Code Online (Sandbox Code Playgroud)

那么这里发生的是,如果你将一堆用户添加到这样的组:

g = Group()
g.users = [User(), User(), User()]
session.add(g)
session.commit()
Run Code Online (Sandbox Code Playgroud)

然后尝试删除该组

session.delete(g)
session.commit()
Run Code Online (Sandbox Code Playgroud)

您将收到某种形式的此错误:

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

删除关系的第二个版本(在我的情况下是动态的)解决了这个问题.我甚至不确定从何处开始理解为什么会发生这种情况.在我的SQLAlchemy模型中,我在很多情况下一直使用两种版本的各种关系,以便在给定情况下轻松使用最合适的查询策略.这是第一次引发意外问题.

欢迎任何建议.

zzz*_*eek 11

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

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')
Run Code Online (Sandbox Code Playgroud)

如果你仍然希望让两种关系处理某种程度的突变,你需要仔细地做这件事,因为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')
Run Code Online (Sandbox Code Playgroud)