Skip to content

Instantly share code, notes, and snippets.

@charlax
Created December 18, 2012 17:20
Show Gist options
  • Save charlax/4329926 to your computer and use it in GitHub Desktop.
Save charlax/4329926 to your computer and use it in GitHub Desktop.
Keeping deletion atomic in spite of model method calling `commit()`.
from sqlalchemy import Column, Integer, Unicode
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
Session = scoped_session(sessionmaker())
class User(Base):
__tablename__ = 'users_test_transaction'
id = Column(Integer, primary_key=True)
name = Column(Unicode(200))
password = Column(Unicode(200))
def delete_password(self):
self.password = ""
# Not sure if this is right, but my code has a lot of commit in a
# model's method. This prevents me from using begin_nested().
Session.commit()
def delete(self):
self.delete_password()
raise TypeError("Nothing")
self.name = "Deleted"
Session.commit()
# Fake view
def delete_user(user):
# I would like this function to happen in a transaction, so that if
# any exception is raised in delete, it rolls back everything. Problem is,
# user.delete() might directly or inderectly call commit().
try:
user.delete()
except:
# Because there's a commit in delete_password, this rollback will do
# nothing.
Session.rollback()
def main():
# Create the table
engine = create_engine('', echo=True)
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
Session.configure(bind=engine)
# Create the user
user = User(name="First Last", password="passwhatever")
Session.add(user)
Session.commit()
# Delete it
delete_user(user)
user = Session.query(User).first()
assert user.name != "Deleted"
# This raises an exception because a commit prevented the full rollback.
assert user.password != ""
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment