将 SQLAlchemy 事件监听器放置在多对多表上

dav*_*ing 1 python sqlalchemy flask-sqlalchemy

我正在尝试检测何时创建或删除多对多关系,但我无法找出要侦听的正确事件。

假设我有一个User模型和一个Team模型,并且我使用成员资格表来定义哪些用户属于哪些团队。这是一个简单的模式(使用 Flask-SQLAlchemy 的基本模型):

membership_table = db.Table('membership', db.metadata,
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('team_id', db.Integer, db.ForeignKey('team.id')),
    db.PrimaryKeyConstraint('user_id', 'team_id'))

class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
    teams = db.relationship('Team', secondary=membership_table, backref='users')

class Team(db.Model):
    __tablename__ = 'team'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64))
Run Code Online (Sandbox Code Playgroud)

我想要做的是检测某人何时加入或离开团队,并触发一个可以利用此信息执行某些操作的事件(例如在某处发送通知:“戴夫加入洋基队”;“莎拉离开大都会队”)。

我首先尝试将事件直接附加after_insertafter_delete成员资格表,但这只是失败并出现AttributeError: after_delete异常,这或多或少是我所期望的,因为它不是像其他模型一样的模型。

我尝试将set侦听器附加到User.teams

@event.listens_for(User.teams, 'set')
def membership_updated(target, value, oldvalue, initiator):
    # compare `oldvalue` to `newvalue` to determine membership change
Run Code Online (Sandbox Code Playgroud)

但是,当我在团队中添加或删除用户时,此事件根本不会触发

我尝试简单地监听以下更新Team

@event.listens_for(Team, 'after_update')
def test(mapper, connection, target):
    # check current membership via `target.users`
Run Code Online (Sandbox Code Playgroud)

当成员资格发生变化时,这是正确触发的,但问题是我无法真正推理正在发生的事情。也许有人只是简单地编辑了团队名称,而成员身份根本没有改变。如果改变了,又是如何改变的?有人添加或删除了吗?

我有点不知道下一步该去哪里,或者如何获取必要的信息。

Ilj*_*ilä 5

为了“检测某人何时加入或离开团队”,监听关系上的追加删除事件:Team.users

@event.listens_for(Team.users, 'append')
def receive_team_users_append(target, value, initiator):
    print(value.name, 'added to team', target.name)

@event.listens_for(Team.users, 'remove')
def receive_team_users_append(target, value, initiator):
    print(value.name, 'removed from team', target.name)
Run Code Online (Sandbox Code Playgroud)

如果您将一个团队追加到用户的团队集合中,事件处理程序也会触发,这要归功于backref / back_populates两个关系属性之间的镜像操作。