我正在从db.Model
迁移到ndb.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
答案 0 :(得分: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
没有必要检查未来的状态 - 何时 调用hook,未来总会有结果。这是因为 hook实际上是对未来的回调。但是有必要 检查结果是否为无!
PS:在一个事务中,一旦put()调用返回就会调用钩子;交易的成败不会影响他们。有关在成功提交后运行挂钩的方法,请参阅https://developers.google.com/appengine/docs/python/ndb/contextclass#Context_call_on_commit。
答案 1 :(得分: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实例是否具有密钥将无法正常工作,因为新实例似乎在将密钥发送到数据存储区之前获得了密钥。您可以查看source code以查看在创建ndb.Model类的实例时会发生什么。
答案 2 :(得分:0)
如果您在创建模型实例时没有提及键,您可以使用 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
附言- 我不知道这是否适用于 google.cloud.ndb