SQLALchemy" after_insert"不更新目标对象字段 [英] SQLALchemy "after_insert" doesn't update target object fields
问题描述
我有一个模型(见下面的代码),我想在一个对象插入后执行一个函数,将更新对象的一个字段。我使用了 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解决方案我最终通过放弃Mapper事件方法解决了这个问题,并使用Flask的信令支持a>代替。
基本上,你可以在你的模型上注册信号,它们本质上是一个回调函数,当某种特定的事件发生的时候被调用。在我的情况下,事件是在我的模型更新。
配置信号,我将这个方法添加到我的
app.py
file:
$ b $ pre $ def $ on_models_committed模型改变信号
为模型,改变改变:
if change =='insert'and hasattr(model,'__commit_insert__'):
model .__ commit_insert __()$ b $如果改变=='update'和hasattr(model,'__commit_update__'):
model .__ commit_update __()
if change =='delete'and hasattr(model,'__commit_delete__'):
model .__ commit_delete __()
然后,在我的模型中,我添加了这个函数来处理更新事件:
$ 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屋!
查看全文