Audit trail
Some applications, those that deal with medical records for example, need an audit trail. I.e. they need to keep track of every database change. One way to achieve this is by
- time stamping and signing every records of every table
- storing a copy of the current record every time it is updated
- marking new/modified records as "active" and stored records as "inactive".
- identify all modifications of the same record with a UUID
(this solution does not break references)
Here is a simple recipe to implement it:
In the model
Insert, somewhere after you define db, auth and crud:
import uuid
user_id = auth.user.id if auth.user else 0
unique_id = Field('unique_id','boolean',default=uuid.uuid4(),writable=False,readable=False)
active = Field('active','boolean',default=True,writable=False)
created_by = Field('created_by',db.auth_user,default=user_id,writable=False)
created_on = Field('created_on','datetime',default=request.now,writable=False)
modified_by = Field('modified_by',db.auth_user,default=user_id,update=user_id,writable=False)
modified_on = Field('modified_on','datetime',default=request.now,update=request.now,writable=False)
Edit all the tables that need an audit trial as follows:
db.define_table('mytable',...other fields...,unique_id,active,created_by,created_on,modified_by,modified_on)
Reference records by "id" as you would normally do.
Define the following function
def copy_record(table):
def copy_record_aux(form, table=table):
if form.record:
d = dict([(f,form.record[f]) for f in table.fields if not f=='id'])
d['active'] = False
table.insert(**d)
return copy_record_aux
In controllers
Use the following syntax for crud.update. If "id" is valid then when the form is submitted the current record is stored and the updated. If "id" is None or 0, then a new record is created, timestamped and signed.
@auth.requires_login()
def update():
id = request.args(0)
form = crud.update(db.mytable, id, onvalidation=copy_record(db.mytable))
return dict(form=form)
Make sure every time you select records to select only active one
db(db.mytable.active==True)(query).select()
You can select all previous versions of any record by
db(db.mytable.unique_id=='<unique_id>').select(orderby=db.mytable.modified_on)
Google App Engine?
yes, it runs on Google App Engine
Comments (4)
0
pwoolf 15 years ago
0
villas 15 years ago
0
aleksdj 15 years ago
0
mrfreeze 15 years ago