Каскадное удаление объекта отношения для удаления только дочернего объекта, но не родительского - PullRequest
0 голосов
/ 26 марта 2020

Я немного озадачен тем, как заставить что-то работать. Я знаю, чего хочу, так что, надеюсь, кто-то может помочь.

У меня есть модель User, которая может быть типа channel или нет. Если это канал, экземпляр User также может иметь администратора - это другой экземпляр User. Чтобы определить это отношение, у меня есть AdminRelationship. Я запутался, когда узнал, какой родительский объект, а какой дочерний, и как получить желаемое поведение при удалении. Чтобы удалить объект AdminRelationship, оставляющий объекты User в такте, и удалить объекты AdminRelationship при удалении User связанного с ним объекта.

class UserRelationship(Base):
    __tablename__ = 'userrelationship'
    id = Column(Integer, primary_key=True)
    follows_id = Column(Integer, ForeignKey('user.id'))
    follower_id = Column(Integer, ForeignKey('user.id'))
    followed = relationship("User", foreign_keys=[follows_id])
    follower = relationship("User", foreign_keys=[follower_id])
    budget = Column(Float(decimal_return_scale=8), default=0)
    trade_size_percentage = Column(Float(decimal_return_scale=2), default=2)
    approved = Column(Boolean(), default=False)
    extend_existing = True```

class AdminRelationship(Base):
    __tablename__ = 'adminrelationship'
    id = Column(Integer, primary_key=True)
    admin_id = Column(Integer, ForeignKey('user.id'))
    channel_id = Column(Integer, ForeignKey('user.id'))
    admin = relationship("User", foreign_keys=[admin_id], cascade='delete')
    channel = relationship("User", foreign_keys=[channel_id], cascade='delete')

class User(Base):
    type = Column(String(64), index=True)
    channels = relationship('AdminRelationship',
                            primaryjoin=(AdminRelationship.admin_id == id),
                            backref=backref('owner', cascade="all, delete"),
                            lazy='dynamic',
                            cascade='all, delete')
    follows = relationship('UserRelationship',
                           primaryjoin=(UserRelationship.follower_id == id),
                           backref=backref('followers'),
                           lazy='dynamic',
                           cascade='all, delete')

Что я хочу, чтобы произошло

У меня есть функции, которые создают объект AdminRelationship и проверяют администраторов на канале, но я не могу заставить работать свою функцию remove_admin(). В конечном счете, вызов user.remove_admin(some_user) должен удалить объект AdminRelationship. Кроме того, если я удаляю экземпляр User, он должен удалять объекты AdminRelationship, связанные с ним.

** Что происходит в настоящее время **

Когда я вызываю мою функцию remove_admin() Я получаю сообщение об ошибке:

sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) update
or delete on table "user" violates foreign key constraint "userrelationship_follows_id_f
key" on table "userrelationship"

Следует отметить, что если пользователь является администратором другого пользователя, он также следует за этим пользователем ...

Соответствующие функции, ниже. follow и unfollow оба работают, add_admin работает, но remove_admin выдает ошибку:

def follow(self, user, budget=0):
    if not self.is_following(user):
        new_follow = UserRelationship(budget=budget, followed=user, follower=self)
        self.follows.append(new_follow)
        db.commit()
        return new_follow

def unfollow(self, user):
    if self.is_following(user):
        relationship = self.follows.filter(UserRelationship.followed == user).first()
        db.delete(relationship)
        db.commit()

def add_admin(self, user):
    if not user.is_admin(self):
        new_admin = AdminRelationship(admin=user, channel=self)
        user.channels.append(new_admin)
        db.commit()
        return new_admin
    else:
        return None

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...