Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disabling committing object changes in SQLAlchemy

I'm using SQLAlchemy in project that is not a web application. It is a server application that loads number of different objects from database and modifies them locally, but don't want to save those updates to the database each time a commit is issued. I was previously working with Django ORM for some web projects and found it better suited for what I'm trying to achieve. In Django ORM I could .save() each object whenever I wanted without saving other things I may not want to save. I understand why it works like this in SQLAlchemy, but I wonder how I could do this in the Django-like way?


Update: To make it easier to understand what I'm trying to achieve, I'll provide you an example.

This is how it works actually:

a = MyModel.query.get(1)
b = MyModel.query.get(1)

a.somefield = 1
b.somefield = 2

# this will save both of changed models
session.commit()

This is how I want it to work:

a = MyModel.query.get(1)
b = MyModel.query.get(1)

a.somefield = 1
b.somefield = 2

a.save()
# I didn't want to save b, changes of b weren't committed

I want to have greater control of what is actually saved. I want to save changes of each object every 5 minute or so.

like image 915
kjagiello Avatar asked Jul 25 '12 10:07

kjagiello


2 Answers

I use something like:

class BaseModel(object):
    def save(self, commit=True):
        # this part can be optimized.
        try:
            db.session.add(self)
        except FlushError:
            # In case of an update operation.
            pass

        if commit:
            db.session.commit()

    def delete(self, commit=True):
        db.session.delete(self)

        if commit:
            db.session.commit()

and then I define my models as:

class User(db.Model, BaseModel)

So, now I can do:

u = User(username='foo', password='bar')
u.save()

This is what you were planning to achieve ?

like image 79
Dhruv Baldawa Avatar answered Nov 07 '22 07:11

Dhruv Baldawa


I am not sure i understand your predicament.

In Django,

foo = MyModel(field1='value1', field2='value2')
foo.save()

or alternatively

foo = MyModel.objects.create(field1='value1', field2='value2')

In SQLAlchemy,

foo = MyModel(field1='value1', field2='value2')
session.add(foo)

At this point you have only added the object to the session and it has not yet committed the transaction. You need to commit only after you have done whatever changes were required

session.commit()

take a look that this link. I think it will make the transition from Django ORM to SqlAlchemy easier.

UPDATE

For such a situation, you could use multiple sessions.

engine = create_engine("postgresql+psycopg2://user:password@localhost/test")
metadata = MetaData(bind=engine)
Session = sessionmaker(bind=engine)
session1 = Session()
session2 = Session()
Base = declarative_base()
class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    age = Column(Integer)
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __repr__(self):
        return "<User('%s','%s')>" % (self.name, self.age)
Base.metadata.create_all(engine)

Created a table 'users' in the 'test' db. Also, 2 session objects, session1 and session2, have been initialized.

a = User('foo','10')
b = User('bar', '20')
session1.add(a)
session1.add(b)
session1.commit()

The table users will now have 2 records

1: foo, 10
2: bar, 20

Fetching the 'foo' record sing session1 and 'bar' using session2.

foo = session1.query(User).filter(User.name == "foo").first()
bar = session2.query(User).filter(User.name == "bar").first()

Making changes to the 2 records

foo.age = 11
bar.age = 21

Now, if you want the changes of foo alone to carry over,

session1.commit()

and for bar,

session2.commit() 
like image 2
Jacob George Avatar answered Nov 07 '22 07:11

Jacob George