Start simple: store the data in-memory in whatever way makes sense, and just write a log file that contains pickled transactions that can be played back. Conceptual sketch of how I would do it follows. This isn't "the" way to do it, just "a" way to do it.

# this is the utility method used by the rest of your code
# to register a new user. maybe this is at module scope in
# the User.py module
def register_user(user):
run_transaction(AddUserTransaction(user))

# this is the actual object that represents the
# transaction
class AddUserTransaction(Transaction):
def __init__(self, user):
Transaction.__init__(self)
self.user = user

# all Transaction objects have an apply() method
def apply(self):
Transaction.apply(self) # invoke base method

# the following MyGlobalUserTable probably just
# stores a couple dicts as indexes over the user info
# e.g. it will have a dict by username, by user ID, etc
MyGlobalUserTable.add_user(self.user)

def run_transaction(t):
# apply the transaction first, then write to the log.
# since if it crashes while running the transaction,
# you don't want to crash again when you play back the log.
t.apply()
transaction_log.append(t)

Here transaction_log.append(t) is some method that will pickle the transaction and append it to some log file. You'll have multiple classes like AddUserTransaction, all derived from Transaction. When you crash and want to play back the transaction log, all you have to do is unpickle the Transaction-derived objects and call apply() on them in the same order. http://docs.python.org/lib/module-pickle.html

Caveats:

-- This will eventually get to have too large a startup cost to play back all the transactions, when you have a huge number of transactions. You can fix it at that point, and you can just replay all the transactions to get the data imported into the new format.

-- The above approach is horrid if you want to launch a new process for every single request. You'd have to replay the transaction log for each incoming request, you'd have a data coherency nightmare, etc. So if you want to use this approach, make sure you're using something that shares one process amongst all requests.

You might also need to worry about whether your server is multithreaded and in that case deal with locking and other crap. I'd suggest going simple with something like Twisted's single-request-at-a-time approach. This isn't as bad as it sounds at first; you just write everything to finish ASAP, and if there's something you need to come back to, you just request the Twisted Reactor to schedule an event. If you have some big blocking thing to do, do it in another thread then notify the Reactor when it's complete (and have the Reactor schedule an event for your code to be notified that the big blocking thing finished).

As you can see, it's not totally trivial and general purpose like the RDBMS + ThingThatGeneratesNastySQLFromObjects approach (aka ORM). But you get more flexibility in your interfaces, and lower overhead. While it can be rewarding and simplifying to work in this way, it could also can lead to over-engineering and/or lost time and effort if you aren't already intimately familiar with the steps in this approach.