Caling setattr on model instance automatically adds it to the dbsession

Issue #3513 resolved
Rob van der Linde created an issue

Not sure if this is a bug or not, but this has been causing us a lot of hassle.

We have a CRUD style rest API and when we update an object (model instance), we call setattr on that model instance to update some fields.

What we are noticing is that when calling setattr, SQLAlchemy always seems to be adding the object to the DBSession automatically so that when we check out DBSession.dirty, the object was put into the session simply by calling setattr.

We have looked at alternative methods, like directly updating __dict__ but that doesn't always work with m2m fields.

Is this a bug? is this expected behaviour? Is there anything else we can do to update an object without automatically getting added to the DBSession.

Comments (7)

  1. Rob van der Linde reporter

    Hi, I looked at this but it doesn't seem to be the backref behaviour you are mentioning.

    To help explain this, I have created a simple example to showcase this bug, using only one model with no relationships at all, I can still trigger it.

    I am using scoped_session, not sure if that is the issue, but please if you could have a look:

    https://github.com/robvdl/sa_attr_bug/blob/master/bug.py

  2. Rob van der Linde reporter

    Note that it doesn't seem to be scoped_session causing this, if I replace my session line with this:

    Session = sessionmaker(bind=engine)()

    instead of this:

    Session = scoped_session(sessionmaker(bind=engine))

    then it still adds the object to the dbsession when I set a property on it.

  3. Mike Bayer repo owner

    I don't understand. You are adding the object to the session right here:

    Session.add(u)
    

    so it's in the session. It will not be removed until you call session.close() , session.expunge(u), or session.expunge_all(). Why is that surprising?

  4. Rob van der Linde reporter

    It looks like I figured it out, it has to do with object states, when you query an object or just created one, then it's still bound to the session (in dbsession.identity_set), so that when you change a property on that object it gets added automatically to the session.

    Calling dbsession.close() before changing the property, fixes it for me.

  5. Log in to comment