sqlachemy多对多:删除不起作用,删除太多

时间:2019-12-19 20:15:07

标签: python database sqlalchemy many-to-many flask-sqlalchemy

我正在研究一个项目,其中包括链接两个类:User和Group。
一个用户可以属于某些组,每个组可以具有一些用户。

因此,我创建了第三个表:group_guest,用于保存user_id和group_id。
创建用户1,用户2,组1和组2时,可以将用户1和组2添加到用户1。
并将group1添加到user2

问题:那么我不能仅从user1中删除group1 并且删除group1不合适:user2没有更多的组了:/

我几乎尝试了所有组合:级联,后向引用,删除孤立项...
如果有人有想法...我应该修改模型吗?
我将不胜感激!

代码:

from app import db  
from flask_login import UserMixin  

group_guest = db.Table('group_guest',  
                       db.Column('user_id', db.Integer, db.ForeignKey('user.id')),  
                       db.Column('group_id', db.Integer, db.ForeignKey('group.id'))  
                       )


class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)

    group_guest_group_id = db.relationship(
        "Group",
        secondary=group_guest,
        back_populates="group_guest_user_id",
        cascade="all, delete",
        lazy='dynamic'
    )


class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    entitled = db.Column(db.String(64))

    group_guest_user_id = db.relationship(
        "User",
        secondary=group_guest,
        back_populates="group_guest_group_id",
        lazy='dynamic'
    )

然后:

user1.group_guest_group_id.remove(group1)
db.session.commit()
user1.guested_group().all()

(在我看来)它应该仅返回group2,但同时返回两者

1 个答案:

答案 0 :(得分:2)

您似乎希望在整个表之间建立不对称关系:

  • 如果您删除User,那么显然也应该删除该user-group的所有User二级引用,即级联在二级表中。
  • 但是,如果组中至少有一个Group,则您不希望删除User,删除活动的Group会引起完整性错误。

在这种情况下,您可以尝试以下操作:

group_guest = db.Table('group_guest',  
                   db.Column('user_id', db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'), primary_key=True),  
                   db.Column('group_id', db.Integer, db.ForeignKey('group.id', ondelete='RESTRICT'), primary_key=True)
                   )

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)

    group_guest_group_id = db.relationship("Group",
        secondary=group_guest,
        back_populates="group_guest_user_id",
        passive_deletes='all', lazy='dynamic'
    )


class Group(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    entitled = db.Column(db.String(64))

    group_guest_user_id = db.relationship("User",
        secondary=group_guest,
        back_populates="group_guest_group_id",
        passive_deletes='all', lazy='dynamic'
    )

被动删除可防止SQLAlchemy自动执行级联删除,并且由ForeignKey的'ondelete'指定的数据库低级指令直接指示操作。

由于辅助表上的主键不能为NULL,因此无论如何您都无法删除父Group。我喜欢ondelete='Restrict'行,因为它明确说明了规则,并且以后再次访问时可以更轻松地进行维护/调试。

编辑

以下对我有效的问题

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
import uuid

Base= declarative_base()

group_guest= Table('group_guest', Base.metadata,
    Column('user_id', Integer, ForeignKey('user.id', ondelete='CASCADE'), primary_key=True),
    Column('group_id', Integer, ForeignKey('group.id', ondelete='RESTRICT'), primary_key=True))

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(64), index=True, unique=True)

    group_guest_group_id = relationship("Group",
        secondary=group_guest,
        back_populates="group_guest_user_id",
        passive_deletes='all', lazy='dynamic'
    )

class Group(Base):
    __tablename__ = 'group'
    id = Column(Integer, primary_key=True)
    entitled = Column(String(64))

    group_guest_user_id = relationship("User",
        secondary=group_guest,
        back_populates="group_guest_group_id",
        passive_deletes='all', lazy='dynamic'
    )


e = create_engine("sqlite://")
Base.metadata.create_all(e)

s = Session(e)

u1 = User(username='A')
u2 = User(username='B')
g1 = Group()
g2 = Group()
s.add_all([u1, u2, g1, g2])
s.commit()

u1.group_guest_group_id.append(g1)
u1.group_guest_group_id.append(g2)
g1.group_guest_user_id.append(u2)
g2.group_guest_user_id.append(u2)

s.add_all([u1, u2, g1, g2])
s.commit()

u1.group_guest_group_id.remove(g1)
s.add(u1)
s.commit()

print([group for group in u1.group_guest_group_id])
print([group for group in u2.group_guest_group_id])