gpt4 book ai didi

python - Sqlalchemy 不会在对象刷新时调用模型的重构器

转载 作者:太空宇宙 更新时间:2023-11-04 00:38:49 25 4
gpt4 key购买 nike

我有一个模型,它应该在初始化时转换一些字段。我尝试使用 sqlalchemy.orm.reconstructor,但遇到了模型自动刷新的问题(或误解)。

这是我的模型示例:

from app import db
from sqlalchemy.orm import reconstructor

t_model = db.Table(
'models',
db.metadata,
dbc.Column('id', db.Integer, primary_key=True),
dbc.Column('value', db.String)
)


class Model(db.Model):

__table__ = t_order_data

def __init__(self, value)
self.value = value

@reconstructor
def init_on_load(self)
"""cast to None if value is empty string"""
self.value = None if not self.value else self.value

def run_db_function(self)
try:
result = db.session.execute(db.func.somefunc('some_param')).fetchone()
except Exception:
db.session.rollback()
raise
else:
db.session.commit()
return result

我的代码做了什么:

model = Model.query.get(1)  # in table this row is id=1, value=''

开始隐式事务并选择模型数据。

model.value  # returns None -- OK

然后我执行功能

model.run_db_function()

它运行 DB 的例程,然后提交事务。

然后,当我尝试访问 value 属性时,sqlalchemy 开始新的隐式事务,在其中再次重新获取该模型。

但是这个时间值不会转换

model.value  # returns '' -- NOT OK

sqlalchqmy ORM的官方文档是关于reconstructor装饰器的:

Designates a method as the “reconstructor”, an __init__-like method that will be called by the ORM after the instance has been loaded from the database or otherwise reconstituted.

根据这个描述,我认为 init_on_load 也应该在重新获取之后被调用,但它并没有发生。

这是错误还是设计行为?如果这是正常行为,我应该如何进行?

最佳答案

引用官方文档:

reconstructor() is a shortcut into a larger system of “instance level” events, which can be subscribed to using the event API - see InstanceEvents for the full API description of these events.

本质上reconstructor()InstanceEvents.load的快捷方式:

Receive an object instance after it has been created via __new__, and after initial attribute population has occurred. ... This typically occurs when the instance is created based on incoming result rows, and is only called once for that instance’s lifetime.

当你commit或回滚默认是使 session 中找到的实例的所有 ORM 控制属性过期。这些实例本身还活着。当您重新获取与 session 中找到的实例匹配的行时,它是 refreshed .一个例子:

In [2]: from sqlalchemy.events import event

In [3]: class Foo(Base):
...: id = Column(Integer, primary_key=True, autoincrement=True)
...: value = Column(Unicode)
...: __tablename__ = 'foo'
...:

添加事件监听器以便我们可以跟踪正在发生的事情

In [5]: @event.listens_for(Foo, 'load')
...: def foo_load(target, context):
...: print('Foo load')
...:

In [6]: @event.listens_for(Foo, 'refresh')
...: def foo_load(target, context, attrs):
...: print('Foo refresh')
...:

In [7]: session.add(Foo(value='test'))

In [8]: session.commit()

构造了Foo实例

In [9]: foo = session.query(Foo).first()
Foo load

In [10]: session.rollback()

在 session 中找到的现在过期的实例被刷新并返回

In [11]: foo2 = session.query(Foo).first()
Foo refresh

两个名称都绑定(bind)到同一个实例

In [12]: foo is foo2
Out[12]: True

In [13]: session.rollback()

对过期实例的属性访问只会导致刷新

In [14]: foo.value
Foo refresh
Out[14]: 'test'

关于python - Sqlalchemy 不会在对象刷新时调用模型的重构器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42805002/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com