I post the detail class here:

Session = scoped_session(sessionmaker())
Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    question_count = Column(Integer)
    questions = relationship('Question', backref='user',
primaryjoin='User.id==Question.user_id')

class QuestionCallback(MapperExtension):
    def after_insert(self, mapper, connection, instance):
         user = instance.user
         user.question_count += 1

class Question(Base):
    __tablename__ = 'questions'
    id = Column(Integer, primary_key=True)
    title = Column(String)
    content = Column(String)
    user_id = Column(Integer, ForeignKey('users.id'))

Now, a user post a new question, after the question has been inserted
to database, the 'user.question_count' should be updated too.

# load user
question  = Question(title='aa', content='bb', user_id=user_id)
Session.add(question)
Session.commit()

What I want is: the question is added to database, and after inserted,
the user of this question should have its 'question_count' column
updated too.

I think the extension should be on the Question class. Because the
flow is:

Insert a question first, then update the associated user. If I write
'before_insert()' on user, it  won't have chance to be invoked.







On 9月6日, 上午2时05分, Michael Bayer <[email protected]> wrote:
> 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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to