[英]How to trigger an event after value change in sqlalchemy
I am defining a mapped class using sqlalchemy.我正在使用 sqlalchemy 定义映射的 class。 It contains three user defined values ( a , b , c ) and one dependend value ( abc ), which is calculated using a , b and c .它包含三个用户定义的值( a , b , c )和一个从属值( abc ),使用a , b和c计算。 I want to attach a listener to a , b and c , which updates abc , when their values are changed.我想将侦听器附加到a , b和c ,当它们的值更改时更新abc 。 Using event.listen(variable.a, 'set', updateFunction)
calls the function, which should update abc .使用event.listen(variable.a, 'set', updateFunction)
调用 function,它应该更新abc 。 Unfortunately the event is fired before the new value is stored in the variable.不幸的是,该事件在新值存储在变量中之前被触发。 Therefore abc will be calculated using the old values.因此abc将使用旧值计算。
Example:例子:
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\t{self.a}")
print(f"target.a \t{target.a}")
print(f"oldvalue \t{oldvalue}")
print(f"value \t\t{value}") #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
Output: Output:
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
How can i update abc using only one function?如何仅使用一个 function 更新abc ? In my application, abc is calculated using seven variables, and i want to avoid writing seven update functions.在我的应用程序中,使用七个变量计算abc ,我想避免编写七个更新函数。 Is there something like event.listen(variable.a, 'after_set', updateFunction)
?有没有类似event.listen(variable.a, 'after_set', updateFunction)
?
Found a similiar quastion after learning about properties: Python getter and setter via @property within SqlAlchemy了解了属性后发现了一个类似的问题: Python getter and setter via @property inside SqlAlchemy
My solution looks like this:我的解决方案如下所示:
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
producing the following output生产以下 output
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.