In addition, the key concept of the unit of work is that it organizes a complete list of all the INSERT, UPDATE and DELETE that will be emitted, as well as the order in which they are emitted before something happens. When before_insert () and after_insert () are called event hooks, this structure has been defined and cannot be changed in any way. The documentation for before_insert () and before_update () mentions that point cannot be affected by this plan - only individual attributes on the object are at hand, and those that have not yet been inserted or updated can be affected here. Any scheme that would like to change the flash plan should use SessionExtension.before_flush. However, there are several ways you can accomplish what you want here without changing your flash plan.
The simplest is what I have already suggested. use MapperExtension.before_insert () on the class "User" and set user.question_count = LEN (user.questions). This assumes that you are mutating user.questions rather than working with Question.user to establish relationships. if you happen to use a "dynamic" relationship (this is not the case) here), you will pull the history for user.questions and calculate what has been added and removed.
The next way is to do pretty much what you think you want here, that is, implement after_insert in the question, but issue the UPDATE statement yourself. This is why “connecting” one of the arguments to the cartographer is the extension methods:
def after_insert(self, mapper, connection, instance): connection.execute(users_table.update().\ values(question_count=users_table.c.question_count +1).\ where(users_table.c.id==instance.user_id))
I would not prefer this approach, since it is rather wasteful for many new Questions added to a single User. So, another option, if you cannot rely on user queries and you would like to avoid many special UPDATEs, actually affect the flash plan using SessionExtension.before_flush:
class MySessionExtension (SessionExtension): def before_flush (self, session, flush_context): for obj in session.new: if isinstance (obj, Question): obj.user.question_count + = 1
for obj in session.deleted: if isinstance(obj, Question): obj.user.question_count -= 1
To combine the "cumulative" approach of the "before_flush" method with the "emit SQL itself" method after_insert (), you can also use SessionExtension.after_flush, calculate everything and emit a single UPDATE mass statement with many parameters. We are probably good at the excess area for this particular situation, but I presented an example of such a scheme in Pycon last year, which you can see at http://bitbucket.org/zzzeek/pycon2010/src/tip/chap5/sessionextension.py .