删除Sqlalchemy上的多对多关系(关联对象)

时间:2014-06-29 16:05:17

标签: python flask sqlalchemy flask-sqlalchemy

我遇到了SqlAlchemy问题。

我只是想删除一个关系。这种关系由关联对象构成。

模型

class User(db.Model, UserMixin):
    id                  = db.Column(db.Integer, primary_key=True)
    email               = db.Column(db.String(255), unique=True)
    username            = db.Column(db.String(255), unique=True)
    password            = db.Column(db.String(255))
    following           = db.relationship('Follower', foreign_keys='Follower.user_id')
    followed_by         = db.relationship('Follower', foreign_keys='Follower.follow_user_id')

    def __repr__(self):
        return '<%s (%i)>' % (self.username, self.id)

class Follower(db.Model):
    __tablename__       = 'followers'

    user_id             = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
    follow_user_id      = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
    created_at          = db.Column(db.DateTime, default=datetime.datetime.now)

    user_followed       = db.relationship("User", primaryjoin=(follow_user_id==User.id))
    user                = db.relationship("User", primaryjoin=(user_id==User.id))

    def __repr__(self):
        return '<%i %i>' % (self.user_id, self.follow_user_id)

我如何添加关系(它有效!):

u1 = # user 1
u2 = # user 2

...

f = Follower()
f.user_followed = u2
u1.following.append(f)
db.session.commit()

我如何尝试删除关系(它不起作用):

f = Follower()
f.user_followed = u2

u1.following.remove(f)
db.session.commit()

错误

ValueError: list.remove(x): x not in list

我理解为什么它不起作用,因为这个Follower()实例不在列表u1.following中。那么,我该如何删除这种关系?

2 个答案:

答案 0 :(得分:1)

您可以覆盖__eq____ne____hash__,以便不是同一个实例但具有相同值的实例,比较和散列相等。

我为此目的使用以下mixin。只需覆盖子类中的compare_value即可返回实际要比较的内容。

from sqlalchemy import inspect

class EqMixin(object):
    def compare_value(self):
        """Return a value or tuple of values to use for comparisons.
        Return instance's primary key by default, which requires that it is persistent in the database.
        Override this in subclasses to get other behavior.
        """
        return inspect(self).identity

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented

        return self.compare_value() == other.compare_value()

    def __ne__(self, other):
        eq = self.__eq__(other)

        if eq is NotImplemented:
            return eq

        return not eq

    def __hash__(self):
        return hash(self.__class__) ^ hash(self.compare_value())

答案 1 :(得分:0)

还可以先尝试查询对象,然后从列表中删除它。

follower_to_be_deleted = db.session.query(Follower).filter_by(user_id=u2.id).first()
u1.following.remove(follower_to_be_deleted)
db.session.commit()