15

我正在从迁移db.Modelndb.Model. 在完成此迁移之前我必须解决的唯一问题是没有Model.is_saved方法。我db.Model.is_saved在我的应用程序中使用来确定是否必须在put/上更新分片计数器delete,以检查创建实体时是否存在冲突键等。

文档说ndb.Model没有等效的is_saved方法。get_or_insert我可以用而不是重新实现一些用例is_saved。但不是全部。

作为一个肮脏的黑客,我可以_in_memory_instance为我通过调用构造函数创建的每个实例设置标志。但这并不能解决我的问题。至少在每次put()通话后我仍然需要更新这个标志。

问题是:是否有更好的方法来确定模型是否在数据存储中持久存在而没有额外的数据存储命中?

编辑1:忘了提:所有实体都有密钥,所以检查对Model._has_complete_key()我不起作用。

编辑 2:经过讨论https://groups.google.com/d/topic/google-appengine/Tm8NDWIvc70/discussion似乎是解决我的问题的唯一方法是使用_post_get_hook/ _post_put_hook。我想知道为什么官方 API 中没有包含这样一个微不足道的东西。

编辑 3:我最终为所有模型创建了下一个基类。现在我可以(几乎)保持我的代码库不变:

class BaseModel(ndb.Model):

    @classmethod
    def _post_get_hook(cls, key, future):
        self = future.get_result()
        if self:
            self._is_saved = bool(key)

    def _post_put_hook(self, future):
        self._is_saved = future.state == future.FINISHING

    def is_saved(self):
        if self._has_complete_key():
            return getattr(self, "_is_saved", False)
        return False
4

3 回答 3

12

要在 NDB 中获得相同的状态,您需要组合使用 post-get-hook 和 post-put-hook 来设置标志。这是一个工作示例:

class Employee(ndb.Model):
  <properties here>

  saved = False  # class variable provides default value

  @classmethod
  def _post_get_hook(cls, key, future):
    obj = future.get_result()
    if obj is not None:
      # test needed because post_get_hook is called even if get() fails!
      obj.saved = True

  def _post_put_hook(self, future):
    self.saved = True

没有必要检查未来的状态——当任何一个钩子被调用时,未来总是有结果的。这是因为钩子实际上是对未来的回调。但是,需要检查其结果是否为无!

PS:在事务中,一旦 put() 调用返回,挂钩就会被调用;交易的成功或失败不会影响他们。有关在成功提交后运行挂钩的方法,请参阅https://developers.google.com/appengine/docs/python/ndb/contextclass#Context_call_on_commit 。

于 2012-08-23T16:20:45.103 回答
2

基于@Tim Hoffmans 的想法,您可以像这样发布挂钩:

class Article(ndb.Model):
    title = ndb.StringProperty()

    is_saved = False

    def _post_put_hook(self, f):
        if f.state == f.FINISHING:
            self.is_saved = True
        else:
            self.is_saved = False


article = Article()
print article.is_saved ## False
article.put()
print article.is_saved ## True

我不能保证它会保留在数据存储中。在谷歌上没有找到任何关于它的东西:)

另一方面,查看 ndb.Model 实例是否具有密钥可能无法正常工作,因为新实例似乎在将密钥发送到数据存储之前就已获得密钥。您可以查看源代码以了解在创建 ndb.Model 类的实例时会发生什么。

于 2012-08-23T07:26:05.957 回答
1

如果您在创建模型实例时未提及键,则可以使用以下实现is_saved()来了解对象是否已写入数据存储区或至少一次。(如果您要从 google.appengine.ext.db 迁移到 google.appengine.ext.ndb,应该是合适的)

使用@fredrik给出的例子,

class Article(ndb.Model):
    title = ndb.StringProperty()
    
    def is_saved(self):
        if self.key:
            return True
        return False

PS - 我不知道这是否适用于 google.cloud.ndb

于 2021-06-11T11:05:34.443 回答