Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy - Session.commit in Session.query loop resets object __dict__

When iterating over session.Query object and calling update, I've noticed that the returned objects no longer have their __dict__'s populated.

E.g.

foos = session.query(Foo)
for foo in foos:
    print "{}".format(foo.__dict__)
    foo.somefield = "somevalue"
    session.add(foo)
    session.commit()  # The next print statement won't show anything

If any of the fields in foo are read during the iteration, though, all of the __dict__ fields become resolved.

E.g.

foos = session.query(Foo)
for foo in foos:
    # Reading any of the fields, causes all of the fields to be resolved.
    foo.somefield
    print "{}".format(foo.__dict__)
    foo.somefield = "somevalue"
    session.add(foo)
    session.commit()  # The next print statement won't show anything

Is there any way to have these values appear in __dict__ without needing to read them first?

like image 332
funseiki Avatar asked Sep 30 '26 03:09

funseiki


1 Answers

The reason this happens is that SQLAlchemy automatically expires your instances after you call commit(). So what happens in order:

  1. you load all Foos
  2. print __dict__, works
  3. commit
  4. all Foos are expired (empties the __dict__ of all Foos)
  5. print __dict__, empty, oops

Reading a field will lazily re-load the instance from the database which is why that works. What you want to do is to turn off expire_on_commit, e.g. if you use sessionmaker:

Session = sessionmaker(expire_on_commit=False)

But be careful that naïve code may no longer do what you expect.

like image 73
univerio Avatar answered Oct 01 '26 17:10

univerio