开发者

Keeping an Audit Trail of any/all Python Database objects in GAE

I'm new to Python. I'm trying to figure out how to emulate an existing application I've coded using PHP and MS-SQL, and re-create the basic back-end functionality on the Google Apps Engine.

One of the things I'm trying to do is emulate the current activity on certain tables I have in MS-SQL, which is an Insert/Delete/Update trigger which inserts a copy of the current (pre-change) record into an audit table, and stamps it with a date and time. I'm then able to query this audit table at a later date to examine the history of changes that the record went through.

I've found the following code here on stackoverflow:

class HistoryEventFieldLevel(db.Model):
    # parent, you don't have to define this
    date = db.DateProperty()
    model = db.StringProperty()
    property = db.StringProperty() # Name of changed property
    action = db.StringProperty( choices=(['insert', 'update', 'delete']) )
    old = db.StringProperty() # Old value for field, empty on insert
    new = db.StringProperty() # New value for field, empty on delete

However, I'm unsure how this code can be app开发者_运维知识库lied to all objects in my new database.

Should I create get() and put() functions for each of my objects, and then in the put() function I create a child object of this class, and set its particular properties?


This is certainly possible, albeit somewhat tricky. Here's a few tips to get you started:

  • Overriding the class's put() method isn't sufficient, since entities can also be stored by calling db.put(), which won't call any methods on the class being written.
  • You can get around this by monkeypatching the SDK to call pre/post call hooks, as documented in my blog post here.
  • Alternately, you can do this at a lower level by implementing RPC hooks, documented in another blog post here.
  • Storing the audit record as a child entity of the modified entity is a good idea, and means you can do it transactionally, though that would require further, more difficult changes.
  • You don't need a record per field. Entities have a natural serialization format, Protocol Buffers, and you can simply store the entity as an encoded Protocol Buffer in the audit record. If you're operating at the model level, use model_to_protobuf to convert a model into a Protocol Buffer.
  • All of the above are far more easily applied to storing the record after it's modified, rather than before it was changed. This shouldn't be an issue, though - if you need the record before it was modified, you can just go back one entry in the audit log.


I am bit out of touch of GAE and also no sdk with me to test it out, so here is some guidelines to given you a hint what you may do.

  1. Create a metaclass AuditMeta which you set in any models you want audited
  2. AuditMeta while creating a new model class should copy Class with new name with "_audit" appended and should also copy the attribute too, which becomes a bit tricky on GAE as attributes are itself descriptors
  3. Add a put method to each such class and on put create a audit object for that class and save it, that way for each row in tableA you will have history in tableA_audit

e.g. a plain python example (without GAE)

import new

class AuditedModel(object):
    def put(self):
        print "saving",self,self.date
        audit = self._audit_class()
        audit.date = self.date
        print "saving audit",audit,audit.date

class AuditMeta(type):
    def __new__(self, name, baseclasses, _dict):
        # create model class, dervied from AuditedModel
        klass = type.__new__(self, name, (AuditedModel,)+baseclasses, _dict)

        # create a audit class, copy of klass
        # we need to copy attributes properly instead of just passing like this
        auditKlass = new.classobj(name+"_audit", baseclasses, _dict)
        klass._audit_class = auditKlass

        return klass

class MyModel(object):
    __metaclass__ = AuditMeta

    date = "XXX"

# create object
a = MyModel()
a.put()

output:

saving <__main__.MyModel object at 0x957aaec> XXX
saving audit <__main__.MyModel_audit object at 0x957ab8c> XXX

Read audit trail code , only 200 lines, to see how they do it for django

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜