sqlalchemy: ObjectdereferencedError sqlalchemy: ObjectdereferencedError database database

sqlalchemy: ObjectdereferencedError


lecture.queues.first().users.append(user)

it means:

the first() method hits the database and produces an object, I'm not following your mappings but I have a guess its a Queue object.

then, you access the "users" collection on Queue.

At this point, Python itself garbage collects Queue - it is not referenced anywhere, once "users" has been returned. This is how reference counting garbage collection works.

Then you attempt to append a "user" to "users". SQLAlchemy has to track the changes to all mapped attributes, if you were to say Queue.name = "some name", SQLAlchemy needs to register that with the parent Queue object so it knows to flush it. If you say Queue.users.append(someuser), same idea, it needs to register the change event with the parent.

SQLAlchemy can't do this, because the Queue is gone. Hence the message is raised. SQLAlchemy has a weakref to the parent here so it knows exactly what has happened (and we can't prevent it because people get very upset when we create unnecessary reference cycles in their object models).

The solution is very easy and also easier to read which is to assign the query result to a variable:

queue = lecture.queues.first()queue.users.append(user)


I did a bunch of refactoring and put in the objects corresponding to some objects during instantiation, which made things a lot neater. Somehow the problem went away.

One thing I did differently was in my many-to-many relationships, I changed the backref to a db.backref():

courses = db.relationship('Course', secondary=courseTable, backref=db.backref('users', lazy='dynamic'))lectures = db.relationship('Lecture', secondary=lectureTable, backref=db.backref('users', lazy='dynamic'))notes = db.relationship('Note', secondary=noteTable, backref=db.backref('users', lazy='dynamic'))queues = db.relationship('Queue', secondary=queueTable, backref=db.backref('users', lazy='dynamic'))