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

Posted

技术标签:

【中文标题】如何在sqlalchemy中的值更改后触发事件【英文标题】:How to trigger an event after value change in sqlalchemy 【发布时间】:2020-12-04 17:56:38 【问题描述】:

我正在使用 sqlalchemy 定义一个映射类。它包含三个用户定义的值(abc)和一个依赖值(abc),其中使用 abc 计算。 我想在 abc 上附加一个监听器,当它们的值发生更改时,它们会更新 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中的值更改后触发事件的主要内容,如果未能解决你的问题,请参考以下文章

当输入的值以编程方式更改时触发更改事件

当我在渲染视图后设置该输入类型的值时,为什么输入类型的更改事件不会触发?

如何限制滑块的值更改事件?

以编程方式更改值时触发Dojo Select onChange事件触发

如何在 PL/SQL 中的触发器后获取复选框的值?

触发更改事件后,Kendo Observable 未更新