提交某种类型的模型后运行功能 [英] Run function after a certain type of model is committed

查看:78
本文介绍了提交某种类型的模型后运行功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在提交Post模型的实例时运行一个函数.我想在它们提交的任何时间运行它,所以我宁愿不要在任何地方显式调用该函数.我该怎么办?

I want to run a function when instances of the Post model are committed. I want to run it any time they are committed, so I'd rather not explicitly call the function everywhere. How can I do this?

def notify_subscribers(post):
    """ send email to subscribers """
    ...

post = Post("Hello World", "This is my first blog entry.")
session.commit() # How to run notify_subscribers with post as argument
                 # as soon as post is committed successfully?

post.title = "Hello World!!1"
session.commit() # Run notify_subscribers once again.

推荐答案

无论您在下面选择哪个选项,SQLAlchemy都带有

No matter which option you chose below, SQLAlchemy comes with a big warning about the after_commit event (which is when both ways send the signal).

当调用after_commit()事件时,会话不在活动事务中,因此无法发出SQL .

The Session is not in an active transaction when the after_commit() event is invoked, and therefore can not emit SQL.

如果您的回调需要查询或提交到数据库,则可能有意外问题.在这种情况下,您可以使用任务队列(例如 Celery )在后台线程中执行此任务(使用单独的会话).无论如何,这可能是正确的方法,因为发送电子邮件会花费很长时间,并且您不希望视图在发生这种情况时等待返回.

If your callback needs to query or commit to the database, it may have unexpected issues. In this case, you could use a task queue such as Celery to execute this in a background thread (with a separate session). This is probably the right way to go anyway, since sending emails takes a long time and you don't want your view to wait to return while it's happening.

Flask-SQLAlchemy 提供了一个信号,您可以收听发送的信号所有插入/更新/删除操作.需要通过设置app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True启用它,因为跟踪修改很昂贵,并且在大多数情况下不需要.

Flask-SQLAlchemy provides a signal you can listen to that sends all the insert/update/delete ops. It needs to be enabled by setting app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True because tracking modifications is expensive and not needed in most cases.

然后监听信号:

from flask_sqlalchemy import models_committed

def notify_subscribers(app, changes):
    new_posts = [target for target, op in changes if isinstance(target, Post) and op in ('insert', 'update')]
    # notify about the new and updated posts

models_committed.connect(notify_subscribers, app)

app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True


您也可以自己实现(主要是通过从Flask-SQLAlchemy复制代码).这有点棘手,因为模型更改发生在 flush 上,而不是发生在 commit 上,因此您需要记录所有发生的更改,然后在提交后使用它们.


You can also implement this yourself (mostly by copying the code from Flask-SQLAlchemy). It's slightly tricky, because model changes occur on flush, not on commit, so you need to record all changes as flushes occur, then use them after the commit.

from sqlalchemy import event

class ModelChangeEvent(object):
    def __init__(self, session, *callbacks):
        self.model_changes = {}
        self.callbacks = callbacks

        event.listen(session, 'before_flush', self.record_ops)
        event.listen(session, 'before_commit', self.record_ops)
        event.listen(session, 'after_commit', self.after_commit)
        event.listen(session, 'after_rollback', self.after_rollback)

    def record_ops(self, session, flush_context=None, instances=None):
        for targets, operation in ((session.new, 'insert'), (session.dirty, 'update'), (session.deleted, 'delete')):
            for target in targets:
                state = inspect(target)
                key = state.identity_key if state.has_identity else id(target)
                self.model_changes[key] = (target, operation)

    def after_commit(self, session):
        if self._model_changes:
            changes = list(self.model_changes.values())

            for callback in self.callbacks:
                callback(changes=changes)

            self.model_changes.clear()

    def after_rollback(self, session):
        self.model_changes.clear()

def notify_subscribers(changes):
    new_posts = [target for target, op in changes if isinstance(target, Post) and op in ('insert', 'update')]
    # notify about new and updated posts

# pass all the callbacks (if you have more than notify_subscribers)
mce = ModelChangeEvent(db.session, notify_subscribers)
# or you can append more callbacks
mce.callbacks.append(my_other_callback)

这篇关于提交某种类型的模型后运行功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆