Hi all, I’ve recently discovered that the order in which events are fired for individual instances is not deterministic. For example, if I add several Author instances to an existing Book then commit the changes, the Book‘s post_update may run before or after the Author‘s post_insert, and the same code might produce different results on successive runs.
Here’s some example code (full gist with models is here: https://gist.github.com/chadrik/c3fff520bd41a48f0a57): @event.listens_for(Book, 'after_update')def book_after_update(mapper, connection, instance): print "after_update", instance, instance.authors @event.listens_for(Book, 'after_insert')def book_after_insert(mapper, connection, instance): print "after_insert", instance, instance.authors @event.listens_for(Author, 'after_insert')def author_after_insert(mapper, connection, instance): print "after_insert", instance def test(): Base.metadata.create_all(engine) book = Book(title='sqlalchemy for dummies') session = Session() session.add(book) session.commit() john = Author(name='John Doe') jane = Author(name='Jane Doe') book.authors = [john, jane] book2 = Book(title='sqlalchemy pro tips') book2.authors = [john] session.add(book2) session.commit() if __name__ == '__main__': test() running test() might print: after_insert Book(1) [] after_insert Author(1) after_insert Author(2) after_insert Book(2) [Author(1)] after_update Book(1) [Author(1), Author(2)] or it might print: after_insert Book(1) [] after_insert Book(2) [Author(None)] after_update Book(1) [Author(None), Author(None)] after_insert Author(1) after_insert Author(2) it can be tricky to consistently reproduce the behavior. sometimes successive runs change randomly with no intervention, sometimes it requires changing a single line of unrelated code, like a comment (I guess this has something to do with python’s byte-compiling and hashing). sometimes a test that will run consistently in the same order using python -m "sqlbooks" will run consistently in a different order using python -c "import sqlbooks;sqlbooks.test()" setting __mapper_args__ = {'batch': False} did not help. it seems that internally sqlalchemy is using unordered containers like dicts or sets when managing the instances passed to these events. my question is: is it possible to provide a meaningful and consistent order to these events? ideally, for my case, I’m hoping to have the Author’s post_insert run before the Book’s post_update, such that the Author’s auto-incrementing id’s are available (you’ll notice in the two output blocks that I pasted, that in the second it prints Author(None)) where None should be the integer id. Also note that the relationship between Book and Author is many-to-many and handled by a secondary table, so no data is persisted to the db for the book table. I assume the post_update is purely to notify me that the Book.authors relationship changed, and as such, it would be highly convenient if the items which were added to the relationship were already inserted and had their primary keys. thanks, chad -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.
