2

I have the following SQLAlchemy Model:

class MyObject2(db.Model, Timestamp):
    id = db.Column(UUIDType(binary=False), nullable=False, primary_key=True) 
    myobj1_id = db.Column(UUIDType(binary=False), db.ForeignKey(MyObject1.id), nullable=False) 
    name = db.Column(db.String(25))

    def __init__(self, myobj1_id, name=None): 
        self.id = uuid.uuid4() 
        self.myobj1_id = myobj1_id
        self.name = name

    @classmethod
    def create(cls, myobj1, name=None):
        try:
            myobj2 = cls(myobj1_id=myobj1.id, name=name)
            db.session.add(myobj2)
            db.session.commit()
            print myobj2     #<=========== LOOK AT THIS LINE!
            return myobj2
        except Exception:
            db.session.rollback()
            raise
        finally:
            db.session.close()

Notice that there is an extraneous print statement in there. See? It doesn't really do anything. Oh well.

Now, here is the code that calls the create() method to create an instance of the model:

myobj2 = MyObject2.create(myobj1=myobj1, name='Hello') 
serialized_myobj_2 = MyObject2Serializer(myobj2).data

All this works fine. But as soon as I remove the unnecessary print statement, I get the following error in the last line of the caller:

Instance <MyObject2 at 0x7ff804ac5710> is not bound to a Session; attribute refresh operation cannot proceed

Why? How does the absence of the print statement cause this bug? When I googled around for this error, I found this post. But the solution given there -- to call session.expunge_all() right beforesession.close()` -- didn't work for me.

What's the solution to getting rid of that print statement without breaking my code?

Saqib Ali
  • 11,931
  • 41
  • 133
  • 272
  • Please include your `Session` configuration, if any. In its default configuration SQLAlchemy `Session` [expires all database loaded state on commit](http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#committing). That's why the print matters; it causes an implicit refresh, before the session is closed for good. Having methods such as your `create()` handle the session's/transaction's lifetime is a bit of an antipattern: http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-close-it. – Ilja Everilä Mar 09 '18 at 08:11
  • Iljia, there is no explicit session configuration. Here are the only two other methods of the `MyObject2` class that I omitted in my original post: https://gist.github.com/saqib-zmi/5e093b6671d43b913c308a0a05b07fc6 – Saqib Ali Mar 09 '18 at 17:25
  • Gravedigging, but putting `expunge_all()` before `close()` is too late. It is `commit()` (or `rollback()`) that expires the attributes. In fact `close()` implicitly expunges all objects, but since you have explicitly committed or rollbacked, the attrs are gone. – Ilja Everilä Nov 14 '18 at 11:07

0 Answers0