如何在sqlalchemy中的值更改后触发事件
Posted
技术标签:
【中文标题】如何在sqlalchemy中的值更改后触发事件【英文标题】:How to trigger an event after value change in sqlalchemy 【发布时间】:2020-12-04 17:56:38 【问题描述】:我正在使用 sqlalchemy 定义一个映射类。它包含三个用户定义的值(a、b、c)和一个依赖值(abc),其中使用 a、b 和 c 计算。
我想在 a、b 和 c 上附加一个监听器,当它们的值发生更改时,它们会更新 abc .
使用event.listen(variable.a, 'set', updateFunction)
调用该函数,该函数应该更新abc。不幸的是,该事件在新值存储在变量中之前触发。因此 abc 将使用旧值进行计算。
例子:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, Numeric, Sequence
from sqlalchemy import event
base = declarative_base()
class demo(base):
__tablename__ = 'demo'
id = Column(Integer, Sequence('some_id_seq'), primary_key=True)
a = Column(Integer)
b = Column(Integer)
c = Column(Integer)
abc = Column(Numeric) #calculated from a, b, and c
def __init__(self, A, B, C):
self.a = A
self.b = B
self.c = C
self.calcABC() #initial calculation of abc
event.listen(demo.a, 'set', self.calcABCEvent, named=True)
event.listen(demo.b, 'set', self.calcABCEvent, named=True)
event.listen(demo.c, 'set', self.calcABCEvent, named=True)
#super complicated formular
def calcABC(self):
self.abc = ( self.a + self.b ) * self.c
#This event ist called, before the new value is set
#Thus the calculation is not correct
def calcABCEvent(self, target, value, oldvalue, initiator):
print("\nevent called")
print(f"self.a \t\tself.a")
print(f"target.a \ttarget.a")
print(f"oldvalue \toldvalue")
print(f"value \t\tvalue") #The new value only appears in value
self.calcABC()
def __str__(self):
return f"(self.a + self.b) * self.c = self.abc"
print("init")
obj = demo(1,2,3)
print(obj) #abc should be (1+2)*3 = 9
print("\nchange a to 4")
obj.a = 4
print("\nchanged object")
print(obj) #abc should be (4+2)*3 = 18
输出:
init
(1 + 2) * 3 = 9
change a to 4
event called
self.a 1
target.a 1
oldvalue 1
value 4
changed object
(4 + 2) * 3 = 9
如何只使用一个函数更新 abc?在我的应用程序中,abc 使用七个变量计算,我想避免编写七个更新函数。有event.listen(variable.a, 'after_set', updateFunction)
之类的吗?
【问题讨论】:
返回计算结果的property
不够吗?
@snakecharmerb 谢谢你的灵感。实际上 hybrid_property
成功了。
【参考方案1】:
了解了属性后发现了一个类似的问题:Python getter and setter via @property within SqlAlchemy
我的解决方案如下所示:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, Numeric, Sequence
from sqlalchemy.ext.hybrid import hybrid_property
base = declarative_base()
class demo(base):
__tablename__ = 'demo'
id = Column(Integer, Sequence('some_id_seq'), primary_key=True)
_a = Column("a", Integer)
_b = Column("b", Integer)
_c = Column("c", Integer)
abc = Column(Numeric) #calculated from a, b, and c
def __init__(self, A, B, C):
self._a = A
self._b = B
self._c = C
self.calcABC() #inital calculation of abc
#super complicated formular
def calcABC(self):
self.abc = ( self._a + self._b ) * self._c
def __str__(self):
return f"(self._a + self._b) * self._c = self.abc"
@hybrid_property
def a(self):
return self._a
@a.setter
def a(self, a):
self._a = a
self.calcABC()
@hybrid_property
def b(self):
return self._b
@b.setter
def b(self, b):
self._b = b
self.calcABC()
@hybrid_property
def c(self):
return self._c
@c.setter
def c(self, c):
self._c = c
self.calcABC()
print("init")
obj = demo(1,2,3)
print(obj) #abc should be (1+2)*3 = 9
print("\nchange a to 4")
obj.a = 4
print(obj) #abc should be (4+2)*3 = 18
print("\nchange b to 5")
obj.b = 5
print(obj) #abc should be (4+5)*3 = 27
print("\nchange c to 6")
obj.c = 5
print(obj) #abc should be (4+5)*6 = 54
产生以下输出
init
(1 + 2) * 3 = 9
change a to 4
(4 + 2) * 3 = 18
change b to 5
(4 + 5) * 3 = 27
change c to 6
(4 + 5) * 6 = 54
Process finished with exit code 0
【讨论】:
以上是关于如何在sqlalchemy中的值更改后触发事件的主要内容,如果未能解决你的问题,请参考以下文章
当我在渲染视图后设置该输入类型的值时,为什么输入类型的更改事件不会触发?