Reputation: 3
I am working on a project including to link two class: User and Group.
A user can be in some groups, and each group can have some users.
So, I created a third table : group_guest, to hold user_id and group_id.
When I create user1, user2, group1 and group2, I can add to user1 the group1 and the group2.
And add to user2 the group1
Issue: then I cannot remove only the group1 from user1 And delete group1 is not fine : user2 has no more group :/
I have tried almost every combinaisons: cascade, backref, delete orphan...
If someone as an idea... Should I modify the model ?
I would be gratefull !
code:
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'
)
Then :
user1.group_guest_group_id.remove(group1)
db.session.commit()
user1.guested_group().all()
It should (in my mind) return only group2 but it return the both
Upvotes: 0
Views: 661
Reputation: 4765
It seems that you want an asymmetric relationship across your table:
User
then obviously all user-group
secondary references to that User
should also be deleted, i.e. cascaded in the secondary table.Group
if at least one User
is present in the group, deleting an active Group
raises an integrity error.In that case you can try the following:
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'
)
Passive deletes prevents SQLAlchemy from auto-executing cascading deletions and the Database low-level instructions specified by 'ondelete' of the foreignKey dictate the action directly.
Since the primary key on the secondary table cannot be NULL then you cannot delete the parent Group
anyway. I just like the ondelete='Restrict'
line since it explictly states the rules and can be easier to maintain/debug later on if you ever revisit it.
the following works for me without issue:
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])
Upvotes: 2