質問
プロパティアクセスはSQLAlchemyでセッションフラッシュをトリガーできますか? 私の期待は、たとえば、 column_property() または @hybrid_property を介してオブジェクトにアタッチされたクエリが、session.Query() を介して作成されたクエリと同じ方法でセッションの自動フラッシュを引き起こすことです。そうではないようです。
以下の簡単な例では、Account に Entry コレクションが含まれています。また、select-sum クエリを公開する column_property() で構築された「バランス」プロパティも提供します。session.flush() が明示的に呼び出された場合にのみ、新しいエントリがアカウントの残高に表示されます。
この動作は最適ではないようです。Account クラスのユーザーは、balance 実装の内部構造を理解していることに基づいて、コード全体に 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
優先出力
session.flush() への明示的な呼び出しを追加せずに、「account.balance: 42」を見たいと思います。