Question
L'accès à une propriété peut-il déclencher un vidage de session dans SQLAlchemy ? Je m'attendrais à ce que, par exemple, les requêtes attachées à un objet via column_property() ou @hybrid_property provoquent un autoflush de la session, de la même manière que les requêtes effectuées via session.Query(). Cela ne semble pas être le cas.
Dans l'exemple simple ci-dessous, un compte contient une collection d'entrées. Il fournit également une propriété "balance", construite avec column_property(), qui expose une requête select-sum. Les nouvelles entrées n'apparaissent dans le solde d'un compte que si session.flush() est appelée explicitement.
Ce comportement semble sous-optimal : les utilisateurs de la classe Account doivent saupoudrer des appels flush() dans leur code en se basant sur la connaissance des aspects internes de l'implémentation de la balance. Si l'implémentation change - par exemple, si "balance" était auparavant une propriété Python @property - des bogues peuvent être introduits même si l'interface Account est essentiellement identique. Existe-t-il une alternative ?
Exemple complet
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])
Production observée
$ 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
Sortie préférée
J'aimerais voir "account.balance : 42", sans ajouter un appel explicite à session.flush().