OK, the problem is that with record versioning, there is a common filter 
applied that excludes records with is_active=False. The _after_update 
callback gets called *after* the is_active field has been set to False 
(which happens when the table's _before_delete callback is called). As a 
result, the records in question no longer show up in the select.

The best workaround is probably to use the _before_delete callback rather 
than the _after_update callback. In the module:

def after_update_event(s, f, table):
    if not ('is_active' in f and f['is_active'] == False) and '_archive' not 
in table:
        table_input = s.select().first()
        current.db.auth_event.insert(time_stamp=current.request.now,
                                     client_ip=current.request.client, 
                                     user_id=current.auth.user_id,
                                     origin='%s/%s' %(current.request.
controller,
                                                      current.request.
function), 
                                     description='ID %s updated in table %s' 
% (table_input.id, table)) 

def before_delete_event(s, table):
    table_input = s.select().first()
    if table_input and '_archive' not in table:
        current.db.auth_event.insert(time_stamp=current.request.now,
                                     client_ip=current.request.client, 
                                     user_id=current.auth.user_id,
                                     origin = '%s/%s' % (current.request.
controller,
                                                         current.request.
function), 
                                     description='ID %s deleted in table %s' 
% (table_input.id, table))

Note, I also added a condition to exclude the '_archive' tables, as you 
probably don't want to log that activity.

In the model file:

for table in db.tables:
    if table != 'auth_event':
        db[table]._after_insert.append(partial(test_event.after_insert_event
, table=table))
        db[table]._after_update.append(partial(test_event.after_update_event
, table=table))
        db[table]._before_delete.insert(0, partial(test_event.
before_delete_event, table=table))

Note, you must insert the _before_delete callback at the beginning of the 
list so it gets called before the is_active field is set to False.

The only downside to this approach is that if a subsequent _before_delete 
callback causes the delete (i.e., update to is_active=False) to be aborted, 
then the delete will still get logged, even though it didn't actually 
happen. If you are using additional callbacks and that is a concern, a 
workaround might be to have the _before_delete callback store the ID of the 
deleted record in the session (but don't log the delete at that point). 
Then, in the _after_update callback, in the case of setting 
is_active=False, fetch the ID from the session.

Anthony


On Friday, April 10, 2015 at 8:12:48 PM UTC-4, 黄祥 wrote:
>
> this min app is work fine, but when you change in modules/test_event.py :
> description = 'ID %s deleted in table %s' % (*s*, table)
> into
> description = 'ID %s deleted in table %s' % (*table_input.id 
> <http://table_input.id>*, table)
>
> it got an error :
>
> description = 'ID %s deleted in table %s' % (table_input.id, table) )
> AttributeError: 'NoneType' object has no attribute 'id'
>
> thanks and best regards,
> stifan
>
>>

-- 
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
--- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to web2py+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to