Python 是否可以使用NDB确定模型是否在数据存储中是持久的?

Python 是否可以使用NDB确定模型是否在数据存储中是持久的?,python,google-app-engine,Python,Google App Engine,我正在从db.Model迁移到ndb.Model。在完成此迁移之前,我必须解决的唯一问题是没有模型。我在应用程序中使用了db.Model.is_saved来确定是否必须在put/delete上更新切分计数器,以检查创建实体时是否存在冲突的键等 文档中说,ndb.Model对于is\u saved方法没有等价物。我可以用get\u或

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

文档中说,
ndb.Model
对于
is\u saved
方法没有等价物。我可以用
get\u或
而不是
is\u saved
重新实现一些用例。但不是所有的

作为一个卑鄙的黑客,我可以为我通过调用构造函数创建的每个实例设置类似于
\u in\u memory\u instance
的标志。但这并不能解决我的问题。至少在每次
put()
调用之后,我仍然必须更新此标志

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

编辑1:忘记提及:所有实体都有密钥,因此请检查
Model.\u has\u complete\u key()
对我不起作用

编辑2:经过这次讨论,似乎解决我问题的唯一方法是使用
\u post\u get\u hook
/
\u post\u put\u 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

基于@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类的实例时会发生什么情况。

要在ndb中获得相同类型的状态,您需要 post get hook和post put hook设置一个标志。这是一张工作票 例如:

class员工(ndb.Model):
saved=False#类变量提供默认值
@类方法
定义后获取挂钩(cls、键、未来):
obj=未来。获取_结果()
如果obj不是无:
#需要测试,因为即使get()失败,也会调用post_get_hook!
obj.saved=True
定义后置挂钩(自身、未来):
self.saved=True
没有必要检查未来的状态——当 所谓钩,未来总是有结果的。这是因为 hook实际上是对未来的回调。然而,有必要这样做 检查其结果是否为无


PS:在事务内部,一旦put()调用返回,就会调用钩子;交易的成功或失败并不影响他们。有关在成功提交后运行钩子的方法,请参阅。

如果在创建模型实例时未提及密钥,则可以使用以下
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

你能检查一下这个对象是否有一个键/id吗?(可能在try/except子句中)。不熟悉NDB模型类,但我记得如果在保存模型实例之前尝试获取其id/键(或者可能返回
None
),db.model会引发错误(或者返回None?)。也不要认为这会导致数据存储受到攻击。如果这样做有效,您可以编写一个类似于
def is_saved(self):return self.key()is None
(或者使用try/except子句执行此操作,如果引发异常则返回True,否则返回False)。如果创建密钥,则检查密钥将不起作用。一种可能的替代方法(但可能不够)是设置一个创建日期标志(设置为auto_now_add=True)。在文档中,“在写入实体之前不会生成自动值;也就是说,这些选项不提供动态默认值。”但是,如果写入失败,将设置该值。虽然您应该知道写入失败;-)或者使用_post_put_hook设置您的标志,表明它已被保存。@TimHoffman,但是如果OP没有显式地创建密钥,那么它就可以工作;P正确,这就是为什么我说“如果你创建了一个密钥,那就工作吧”。我想如果他们正在创建密钥,我会提供一个替代方案;-)它非常接近,可以作为一种解决方法。所以我投+1票。如果不会出现更好的解决方案,我将在几天内接受您的回答。我认为这种方法目前唯一的缺点是,如果已检索实体而不是创建实体,则
将保存
为False
。它不映射到
db。模型
的行为已保存()
。为了完整起见,您可能需要添加一个
\u post\u get\u hook
方法,该方法还将设置保存为True。如前所述,这对通过查询/gql检索的实体不起作用,因为没有对它们调用\u post\u get\u hook,也没有查询的等效回调(目前)。
class Article(ndb.Model):
    title = ndb.StringProperty()
    
    def is_saved(self):
        if self.key:
            return True
        return False