SQLALchemy" after_insert"不更新目标对象字段 [英] SQLALchemy "after_insert" doesn't update target object fields

查看:298
本文介绍了SQLALchemy" after_insert"不更新目标对象字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模型(见下面的代码),我想在一个对象插入后执行一个函数,将更新对象的一个​​字段。我使用了 after_insert Mapper事件来做到这一点。



我已经确认了 after_insert 使用正确的 audio_text 值更新 event_extract_audio_text()处理程序和目标。但是,一旦事件处理程序执行完毕,就不会为数据库中的对象设置文本值。



代码

 #事件处理程序
def event_extract_audio_text(映射器,连接,目标):

从音频文件中提取文本
audio_text = compute_text_from_audio_file(target.filename)

#用提取的文本更新'text'字段
target.audio_text = audio_text

#Model
class SoundsRaw(db.Model):
__tablename__ ='soundsraw'

id = db.Column(db.BigInteger(),primary_key = True,autoincrement = True)
filename = db.Column(db.String(255))
audio_text = db.Column(db.Text())

#事件监听器
event.listen SoundsRaw,'after_insert',event_extract_audio_text)

我也试着调用db.session。 commit()尝试用文本值更新对象,但是我得到了fo下面的堆栈跟踪:

 文件/Users/alexmarse/.virtualenvs/techmuseum/lib/python2.7/site-packages/ sqlalchemy / orm / session.py,第219行,在_assert_active 
中引发sa_exc.ResourceClosedError(closed_msg)

ResourceClosedError:该交易已关闭



有什么想法?

软件版本



SQLAlchemy 0.9.4
Flask 0.10.1
Flask-SQLAlchemy 1.0

然后,在我的模型中,我添加了这个函数来处理更新事件:

$ p $ #事件方法
def __commit_update __(self):

#create a新的数据库会话,它避免了ResourceClosedError
session = create_db_session()

m techmuseum.modules.sensors.models import SoundsRaw
#通过uuid获取SoundsRaw记录(self包含被更新的对象
#但是我们不能只更新/提交自我 - 我们会得到一个ResourceClosedError)
sound = session.query(SoundsRaw).filter_by(uuid = self.uuid).first()

从音频文件中提取文本
audio_text = compute_text_from_audio_file(声音)

#更新声音的文本字段
sound.text = audio_text

#将更新提交到声音
会话。添加(声音)
session.commit()

def create_db_session():
#从sqlalchemy创建一个新的Session
从sqlalchemy导入create_engine
。 orm import sessionmaker
$ b psql_url = app.config ['SQLALCHEMY_DATABASE_URI']
some_engine = create_engine(psql_url)

#创建一个配置的会话类
session = sessionmaker(bind = some_engine)

返回n session


I have a model (see code below) on which I want to execute a function after an object is inserted that will update one of the object's fields. I'm using the after_insert Mapper Event to do this.

I've confirmed that the after_insert properly calls the event_extract_audio_text() handler, and the target is getting updated with the correct audio_text value. However, once the event handler finishes executing, the text value is not set for the object in the database.

Code

# Event handler
def event_extract_audio_text(mapper, connect, target):

    # Extract text from audio file
    audio_text = compute_text_from_audio_file(target.filename)

    # Update the 'text' field with extracted text
    target.audio_text = audio_text

# Model
class SoundsRaw(db.Model):
    __tablename__ = 'soundsraw'

    id = db.Column(db.BigInteger(), primary_key=True, autoincrement=True)
    filename = db.Column(db.String(255))
    audio_text = db.Column(db.Text())

# Event listener
event.listen(SoundsRaw, 'after_insert', event_extract_audio_text)

I've also tried calling db.session.commit() to try to update the object with the text value, but then I get the following stack trace:

File "/Users/alexmarse/.virtualenvs/techmuseum/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 219, in _assert_active
raise sa_exc.ResourceClosedError(closed_msg)

ResourceClosedError: This transaction is closed

Any ideas?

Software versions

SQLAlchemy 0.9.4 Flask 0.10.1 Flask-SQLAlchemy 1.0

解决方案

I ended up solving this by ditching the Mapper Event approach and using Flask's Signalling Support instead.

Basically, you can register "signals" on your model, which are essentially callback functions that are called whenever a specific kind of event happens. In my case, the event is an "update" on my model.

To configure the signals, I added this method to my app.py file:

def on_models_committed(sender, changes):
    """Handler for model change signals"""
    for model, change in changes:
        if change == 'insert' and hasattr(model, '__commit_insert__'):
            model.__commit_insert__()
        if change == 'update' and hasattr(model, '__commit_update__'):
            model.__commit_update__()
        if change == 'delete' and hasattr(model, '__commit_delete__'):
            model.__commit_delete__()

Then, on my model, I added this function to handle the update event:

 # Event methods
def __commit_update__(self):

    # create a new db session, which avoids the ResourceClosedError
    session = create_db_session()

    from techmuseum.modules.sensors.models import SoundsRaw
    # Get the SoundsRaw record by uuid (self contains the object being updated, 
    # but we can't just update/commit self -- we'd get a ResourceClosedError)
    sound = session.query(SoundsRaw).filter_by(uuid=self.uuid).first()

    # Extract text from audio file
    audio_text = compute_text_from_audio_file(sound)

    # Update the 'text' field of the sound
    sound.text = audio_text

    # Commit the update to the sound
    session.add(sound)
    session.commit()

def create_db_session():
    # create a new Session
    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker

    psql_url = app.config['SQLALCHEMY_DATABASE_URI']
    some_engine = create_engine(psql_url)

    # create a configured "Session" class
    session = sessionmaker(bind=some_engine)

    return session

这篇关于SQLALchemy" after_insert"不更新目标对象字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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