4.2 Undoing Changes

Some types of Storage support undoing a transaction even after it's been committed. You can tell if this is the case by calling the supportsUndo() method of the DB instance, which returns true if the underlying storage supports undo. Alternatively you can call the supportsUndo() method on the underlying storage instance.

If a database supports undo, then the undoLog(start, end[, func]) method on the DB instance returns the log of past transactions, returning transactions between the times start and end, measured in seconds from the epoch. If present, func is a function that acts as a filter on the transactions to be returned; it's passed a dictionary representing each transaction, and only transactions for which func returns true will be included in the list of transactions returned to the caller of undoLog(). The dictionary contains keys for various properties of the transaction. The most important keys are "id", for the transaction ID, and "time", for the time at which the transaction was committed.

>>> print storage.undoLog(0, sys.maxint)
[{'description': '',
  'id': 'AzpGEGqU/0QAAAAAAAAGMA',
  'time': 981126744.98,
  'user_name': ''},
 {'description': '',
  'id': 'AzpGC/hUOKoAAAAAAAAFDQ',
  'time': 981126478.202,
  'user_name': ''}
  ...

To store a description and a user name on a commit, get the current transaction and call the note(text) method to store a description, and the setUser(user_name) method to store the user name. While setUser() overwrites the current user name and replaces it with the new value, the note() method always adds the text to the transaction's description, so it can be called several times to log several different changes made in the course of a single transaction.

get_transaction().setUser('amk')
get_transaction().note('Change ownership')

To undo a transaction, call the DB.undo(id) method, passing it the ID of the transaction to undo. If the transaction can't be undone, a ZODB.POSException.UndoError exception will be raised, with the message ``non-undoable transaction''. Usually this will happen because later transactions modified the objects affected by the transaction you're trying to undo.