简体   繁体   English

sqlalchemy中的值更改后如何触发事件

[英]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 .它包含三个用户定义的值( abc )和一个从属值( abc ),使用abc计算。 I want to attach a listener to a , b and c , which updates abc , when their values are changed.我想将侦听器附加到abc ,当它们的值更改时更新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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM