问题
属性访问可以触发 SQLAlchemy 中的会话刷新吗?我的期望是,例如,通过 column_property() 或 @hybrid_property 附加到对象的查询会导致会话自动刷新,就像通过 session.Query() 进行的查询一样。情况似乎并非如此。
在下面的简单示例中,一个 Account 包含一个 Entry 集合。它还提供了一个使用 column_property() 构造的“平衡”属性,该属性公开了一个选择和查询。如果 session.flush() 被显式调用,新条目只会出现在帐户的余额中。
这种行为似乎不是最理想的:Account 类的用户需要根据对余额实现内部的了解,在他们的代码中散布 flush() 调用。如果实现发生变化——例如,如果“balance”以前是 Python @property——即使 Account 接口本质上是相同的,也会引入错误。有替代方案吗?
完整示例
import sys
import sqlalchemy as sa
import sqlalchemy.sql
import sqlalchemy.orm
import sqlalchemy.ext.declarative
Base = sa.ext.declarative.declarative_base()
class Entry(Base):
__tablename__ = "entries"
id = sa.Column(sa.Integer, primary_key=True)
value = sa.Column(sa.Numeric, primary_key=True)
account_id = sa.Column(sa.Integer, sa.ForeignKey("accounts.id"))
account = sa.orm.relationship("Account", backref="entries")
class Account(Base):
__tablename__ = "accounts"
id = sa.Column(sa.Integer, primary_key=True)
balance = sa.orm.column_property(
sa.sql.select([sa.sql.func.sum(Entry.value)])
.where(Entry.account_id == id)
)
def example(database_url):
# connect to the database and prepare the schema
engine = sa.create_engine(database_url)
session = sa.orm.sessionmaker(bind=engine)()
Base.metadata.create_all(bind = engine)
# add an entry to an account
account = Account()
account.entries.append(Entry(value = 42))
session.add(account)
# and look for that entry in the balance
print "account.balance:", account.balance
assert account.balance == 42
if __name__ == "__main__":
example(sys.argv[1])
观察到的输出
$ python sa_column_property_example.py postgres:///za_test
account.balance: None
Traceback (most recent call last):
File "sa_column_property_example.py", line 46, in <module>
example(sys.argv[1])
File "sa_column_property_example.py", line 43, in example
assert account.balance == 42
AssertionError
首选输出
我希望看到“account.balance: 42”,而不需要添加对 session.flush() 的显式调用。