【问题标题】:How to read old property values in a _pre_put_hook如何读取 _pre_put_hook 中的旧属性值
【发布时间】:2014-01-22 20:02:06
【问题描述】:

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

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)))

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

【问题讨论】:

  • 您能再补充一点上下文吗?也许是完整的模型?为什么(再次)从钩子内部获取()实体?如果你想 put() 一个改变的实体,我想你已经获取了它。
  • 试试 self.key.get(use_cache=False),因为上下文缓存会引用同一个实体(self)。
  • 使用_post_get_hook 存储原始值,以便在运行_pre_put_hook 时可以使用它们。
  • 感谢@DavidBennett:您的self.key.get(use_cache=False) 建议效果很好!我在应用 put() 之前从数据存储中获取对象中的旧值。

标签: google-app-engine google-cloud-datastore app-engine-ndb


【解决方案1】:

编辑:

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

  __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

在您第一次阅读实体时对其进行克隆:

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

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

我们重写了两种不同的模型方法来实现这一点:

@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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-06
    • 1970-01-01
    • 1970-01-01
    • 2015-11-19
    • 2012-03-04
    • 2020-01-07
    • 2011-03-10
    相关资源
    最近更新 更多