在GAE中保留任何/所有Python数据库对象的审计跟踪

时间:2011-06-14 21:52:17

标签: python google-app-engine object audit

我是Python的新手。我正在试图弄清楚如何模拟我使用PHP和MS-SQL编码的现有应用程序,并在Google Apps Engine上重新创建基本的后端功能。

我要做的其中一件事是模拟我在MS-SQL中的某些表上的当前活动,这是一个插入/删除/更新触发器,它插入当前(更改前)记录的副本进入审计表,并用日期和时间标记。然后,我可以在以后查询此审计表,以检查记录所经历的更改的历史记录。

我在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

但是,我不确定如何将此代码应用于新数据库中的所有对象。

我应该为每个对象创建get()和put()函数,然后在put()函数中创建这个类的子对象,并设置它的特定属性吗?

2 个答案:

答案 0 :(得分:1)

这当然是可能的,尽管有些棘手。以下是一些可以帮助您入门的提示:

  • 覆盖类的put()方法是不够的,因为实体也可以通过调用db.put()来存储,{{1}}不会调用正在编写的类上的任何方法。
  • 你可以通过monkeypatching SDK来调用前/后调用挂钩来解决这个问题,如我的博文here中所述。
  • 或者,您可以通过实施RPC挂钩在较低级别执行此操作,并在另一篇博文here中进行了说明。
  • 将审核记录存储为修改后的实体的子实体是一个好主意,这意味着您可以在事务上执行此操作,但这需要进行更多,更困难的更改。
  • 每个字段不需要记录。实体具有自然的序列化格式Protocol Buffers,您只需将实体存储为审计记录中的编码协议缓冲区即可。如果您在模型级别运行,请使用model_to_protobuf将模型转换为协议缓冲区。
  • 上述所有内容更容易应用于在修改后存储记录,而不是在更改之前。但这不应该是一个问题 - 如果您在修改之前需要记录,您只需返回审核日志中的一个条目。

答案 1 :(得分:0)

我与GAE有点脱节,也没有跟我一起测试它,所以这里有一些指导方针给你一个提示你可能会做什么。

  1. 创建一个在您想要审核的模型中设置的元类AuditMeta
  2. 在创建新模型类时,AuditMeta应该复制具有附加“_audit”的新名称的Class,并且还应该复制该属性,这在GAE上变得有点棘手,因为属性本​​身就是描述符
  3. 为每个这样的类添加一个put方法,并在put上为该类创建一个审计对象并保存它,对于tableA中的每一行,你将在tableA_audit中有历史记录
  4. e.g。一个普通的python示例(没有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()
    

    输出:

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

    阅读audit trail代码,只有200行,看看他们是如何为django做的

相关问题