gpt4 book ai didi

python - 使用 AttributeExtension 自动更新非规范化属性

转载 作者:行者123 更新时间:2023-11-28 16:54:27 25 4
gpt4 key购买 nike

我在使用 AttributeExtension 时遇到了一些问题SQLAlchemy 的。

实际上,我在 Partent 表中存储了一个非规范化的总和属性,因为我经常需要它来进行排序。但是,我希望属性在其中一个子项的值发生更改时得到更新。

不幸的是,从未调用 AttributeExtension 的 set() 方法,因此无法识别更改。使用也更新父级的属性 setter 可能有效,但我想知道如何正确使用 SQLAlchemy 的 AttributeExtension(版本:0.6beta2)。

这是一个演示问题的小(可运行)代码片段:

from sqlalchemy import create_engine, Column, Integer, ForeignKey
from sqlalchemy.orm import relation, scoped_session, sessionmaker, \
AttributeExtension
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:', echo=True)
session = scoped_session(sessionmaker(bind=engine, autoflush=True))
Base = declarative_base()
Base.query = session.query_property()

class ChildrenAttributeExtension(AttributeExtension):
active_history = True

def append(self, state, child, initiator):
parent = state.obj()
parent.sum_of_children += child.value
return child

def remove(self, state, child, initiator):
parent = state.obj()
parent.sum_of_children -= child.value

def set(self, state, child, oldchild, initiator):
print 'set called' # gets never printed
parent = state.obj()
parent.sum_of_children += -oldchild.value + child.value
return child


class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'), nullable=False)
value = Column(Integer, nullable=False, default=0)


class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
sum_of_children = Column(Integer, nullable=False, default=0)

children = relation('Child', backref='parent',
extension=ChildrenAttributeExtension())

Base.metadata.create_all(engine)

# Add a parent
p = Parent()
session.add(p)
session.commit()

p = Parent.query.first()
assert p.sum_of_children == 0


# Add a child
c = Child(parent=p, value=5)
session.add(c)
session.commit()

p = Parent.query.first()
assert p.sum_of_children == 5

# Change a child
c = Child.query.first()
c.value = 3
session.commit() # extension.set() doesn't get called

p = Parent.query.first()
assert p.sum_of_children == 3 # Assertion fails

感谢您的帮助!
克里斯托夫

最佳答案

据我所知,您正在寻找关于 child 的事件,但更改了 child.value。像这样的东西应该可以解决问题:

class ValueAttributeExtension(AttributeExtension):
...

class Child(Base):
...
value = ColumnProperty(Column(Integer, nullable=False, default=0),
extension=ValueAttributeExtension())

EDIT-1:下面的完整工作示例:

from sqlalchemy import create_engine, Column, Integer, ForeignKey
from sqlalchemy.orm import relation, scoped_session, sessionmaker, AttributeExtension, ColumnProperty
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:', echo=False)
session = scoped_session(sessionmaker(bind=engine, autoflush=True))
Base = declarative_base()
Base.query = session.query_property()

class ValueAttributeExtension(AttributeExtension):
active_history = True

def append(self, state, child, initiator):
assert False, "should not be called"

def remove(self, state, child, initiator):
assert False, "should not be called"

def set(self, state, value, oldvalue, initiator):
print 'set called', state.obj(), value, oldvalue
child = state.obj()
if not(child.parent is None):
child.parent.sum_of_children += -oldvalue + value
return value

class ChildrenAttributeExtension(AttributeExtension):
active_history = True

def append(self, state, child, initiator):
print 'append called', state.obj(), child
parent = state.obj()
parent.sum_of_children += child.value
return child

def remove(self, state, child, initiator):
print 'remove called', state.obj(), child
parent = state.obj()
parent.sum_of_children -= child.value

def set(self, state, child, oldchild, initiator):
print 'set called', state, child, oldchild
parent = state.obj()
parent.parent.sum_of_children += -oldchild.value + child.value
#parent.sum_of_children += -oldchild.value + child.value
return child

class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'), nullable=False)
value = ColumnProperty(Column(Integer, nullable=False, default=0),
extension=ValueAttributeExtension())

class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
sum_of_children = Column(Integer, nullable=False, default=0)

children = relation('Child', backref='parent',
extension=ChildrenAttributeExtension())

Base.metadata.create_all(engine)

# Add a parent
p = Parent()
session.add(p)
session.commit()

p = Parent.query.first()
assert p.sum_of_children == 0


# Add a child
c = Child(parent=p, value=5)
session.add(c)
session.commit()

p = Parent.query.first()
assert p.sum_of_children == 5

# Change a child
#c = Child.query.first()
c.value = 3 # fixed bug: = instead of ==
session.commit() # extension.set() doesn't get called

p = Parent.query.first()
assert p.sum_of_children == 3 # Assertion is OK

关于python - 使用 AttributeExtension 自动更新非规范化属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2296502/

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