On Sep 5, 2010, at 1:27 PM, Freewind wrote: > There are two classes: User and Question > > A user may have many questions, and it also contains a question_count > to record the the count of questions belong to him. > > So, when I add a new question, I want update the question_count of the > user. At first, I do as: > > question = Question(title='aaa', content='bbb') > Session.add(question) > Session.flush() > > user = question.user > ### user is not None > user.question_count += 1 > Session.commit() > > Everything goes well. > > But I wan't to use event callback to do the same thing. As following: > > from sqlalchemy.orm.interfaces import MapperExtension > class Callback(MapperExtension): > def after_insert(self, mapper, connection, instance): > user = instance.user > ### user is None !!! > user.question_count += 1
Not really sure why question.user would be None here if you had set it (in your example above, its not set, unless you have some odd join condition going on), but it would also be more appropriate here for the extension to be on the User class, not Question, using before_insert(). > > 2. If I change that line to: > > Session.query(User).filter_by(id=instance.user_id).one() > > I can get the user successfully, But: the user can't be updated! > > Look I have modified the user: > > user.question_count += 1 > > But there is no 'update' sql printed in the console, and the > 'question_count' are not updated. So, if you were to emit the INSERT statements for both your User and your Question, assuming Question has a foreign key to User, which would INSERT would need to occur first ? The "User" row would already have been inserted here by the time your Question after_insert is invoked (and the fact that you can look it up proves it). People usually use before_insert() which states in its doc that you can't manipulate the flush plan or assume it will change in any way at that point, but I guess I'll make this message much more explicit for all the intra-flush() hooks. > > 3. I try to add 'Session.flush()' or 'Session.commit()' in the > 'after_insert()' method, but both cause errors. The error should be clear here - "Session is already flushing". The extension points are within a transaction, within a flush. Invoking flush() within flush() is not something that is possible, and invoking commit() within flush(), assuming the reentrant flush() issue weren't present, would mean half of the flush is committed, half not, and the transaction would then be incorrectly committed before it was actually committed on the outside. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.