如何读取_pre_put_hook中的旧属性值 [英] How to read old property values in a _pre_put_hook

查看:178
本文介绍了如何读取_pre_put_hook中的旧属性值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实施ndb模型审计,以便所有属性更改都存储在每个模型实例中。这是我选择实现的_pre_put_hook的代码。

  def _pre_put_hook(self):
#save a更新的历史记录
如果不是(self.key是None或self.key.id()是None):
old_object = self.key.get(use_cache = True)
for attr在dir(self)中:
(如果不可调用)getattr(self,attr) ):
logging.debug('UPDATE:{0}'.format(attr))
logging.debug('OLD:{0} NEW:{1}'.format(getattr(old_object, attr),getattr(self,attr)))

问题是old_object始终填充相同自我(对象)的值正在更新。如何在put()被实际创建(_pre_put)之前访问旧对象的属性值?

解决方案

编辑:



我意识到随着时间的推移,我正在做一堆不需要完成的工作(大量的CPU /内存用于复制整个实体并在不需要时传递它们)。这是更新后的版本,它存储了对原始protobuf的引用,并且只在需要时反序列化它。

  __original = None#a shadow - 这个对象的拷贝,所以我们可以看到什么改变...懒惰膨胀
_original_pb = None#这个实体的原始编码Protobuf表示

@property
def _original(self ):

单例将protobuf反序列化为一个新的实体,它看起来像数据库中的原始数据

如果不是self .__ original和self._original_pb:
self .__ original = self .__ class __._ from_pb(self._original_pb)
return self .__ original

@classmethod
def _from_pb(cls,pb,set_key = True ,ent = None,key = None):

保存原始pb的副本,以便我们可以跟踪是否有任何东西在

entity = super ChangesetMixin,cls)._ from_pb(pb,set_key = set_key,ent = ent,key = key)
如果entity._origina l_pb是None而不是entity._projection:
#_from_pb会在我们取消一个新对象的时候被调用(就像通过延期库时一样)
#所以如果我们正在从pb物化并且我们不有一个关键,那么我们没有_original
实体.__ original = None
entity._original_pb = pb
返回实体



当您第一次阅读它时,对实体进行克隆:

将实体复制到在'编译'时间不知道属性名称的Python App Engine数据存储区



并将其放置在实体本身上,以便稍后在需要时引用它。这样,您不必为了进行比较而进行第二次数据存储阅读。



我们重写两个不同的Model方法来实现这一点:

  @classmethod 
def _post_get_hook(cls,key,future):

克隆这个实体,所以我们可以跟踪放置

之间是否有任何变化注意:只有在ndb.Key.get()之后才会调用... NOT从Query
加载时请参阅下面的_from_pb覆盖以了解完整图片

也注意到:在每个key.get()之后都会调用它,不管NDB是否已经缓存了
,这就是为什么我们只做clone()if _original没有设置...

entity = future.get_result()
如果实体不是None并且entity._original是None:
entity._original = clone (实体)

@classmethod
def _from_pb(cls,pb,set_key = True,ent = None,key = None):

clone this实体,所以我们可以跟踪一个在$ puts

之间有所变化这是一种知道何时从数据存储区加载对象的方法QUERY
_post_get_hook仅在直接Key.get()
上调用时没有文档化的钩子在查询结果后被调用

SEE:https://code.google.com/p/appengine-ndb-experiment/issues/detail?id=211

entity = super(BaseModel,cls)._ from_pb(pb,set_key = set_key,ent = ent,key = key)
如果entity.key和entity._original是None:
#_from_pb将被调用如果我们取消一个新对象(就像通过延期库时一样)
#所以如果我们正在从pb物化并且没有键,那么我们没有_biginal
entity._original =克隆(实体)
返回实体


I am trying to implement an ndb model audit so that all changes to properties are stored within each model instance. Here is the code of the _pre_put_hook I chose to implement that.

def _pre_put_hook(self):
    # save a history record for updates
    if not (self.key is None or self.key.id() is None):
        old_object = self.key.get(use_cache=True)
        for attr in dir(self):
            if not callable(getattr(self, attr)) and not attr.startswith("_"):
                if getattr(self, attr) != getattr(old_object, attr):
                    logging.debug('UPDATE: {0}'.format(attr))
                    logging.debug('OLD: {0} NEW: {1}'.format(getattr(old_object, attr), getattr(self, attr)))

The problem is old_object is always populated with the same values of the self (object) being updated. How can I access the property values of the old object BEFORE the put() being actually made (_pre_put)?

解决方案

EDIT:

I realized over time I was doing a bunch of work that didn't need to be done (alot of CPU/memory used copying entire entities and passing them around when may not be needed). Here's the updated version which stores a reference to the original protobuf and only deserializes it if you need it

  __original = None    # a shadow-copy of this object so we can see what changed... lazily inflated
  _original_pb = None  # the original encoded Protobuf representation of this entity

  @property
  def _original(self):
    """
     Singleton to deserialize the protobuf into a new entity that looks like the original from database
    """
    if not self.__original and self._original_pb:
      self.__original = self.__class__._from_pb(self._original_pb)
    return self.__original

  @classmethod
  def _from_pb(cls, pb, set_key=True, ent=None, key=None):
    """
    save copy of original pb so we can track if anything changes between puts
    """
    entity = super(ChangesetMixin, cls)._from_pb(pb, set_key=set_key, ent=ent, key=key)
    if entity._original_pb is None and not entity._projection:
      # _from_pb will get called if we unpickle a new object (like when passing through deferred library)
      #   so if we are being materialized from pb and we don't have a key, then we don't have _original
      entity.__original = None
      entity._original_pb = pb
    return entity


Make a clone of the entity when you first read it:

Copy an entity in Google App Engine datastore in Python without knowing property names at 'compile' time

and put it on the entity itself so it can be referenced later when desired. That way you don't have to do a second datastore read just to make the comparison

We override two different Model methods to make this happen:

@classmethod
def _post_get_hook(cls, key, future):
    """
    clone this entity so we can track if anything changes between puts

    NOTE: this only gets called after a ndb.Key.get() ... NOT when loaded from a Query
      see _from_pb override below to understand the full picture

    also note: this gets called after EVERY key.get()... regardless if NDB had cached it already
      so that's why we're only doing the clone() if _original is not set...
    """
    entity = future.get_result()
    if entity is not None and entity._original is None:
        entity._original = clone(entity)

@classmethod
def _from_pb(cls, pb, set_key=True, ent=None, key=None):
    """
    clone this entity so we can track if anything changes between puts

    this is one way to know when an object loads from a datastore QUERY
      _post_get_hook only gets called on direct Key.get()
      none of the documented hooks are called after query results

    SEE: https://code.google.com/p/appengine-ndb-experiment/issues/detail?id=211
    """
    entity = super(BaseModel, cls)._from_pb(pb, set_key=set_key, ent=ent, key=key)
    if entity.key and entity._original is None:
        # _from_pb will get called if we unpickle a new object (like when passing through deferred library)
        #   so if we are being materialized from pb and we don't have a key, then we don't have _original
        entity._original = clone(entity)
    return entity

这篇关于如何读取_pre_put_hook中的旧属性值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆