Python 谷歌应用引擎NDB post_创建挂钩

Python 谷歌应用引擎NDB post_创建挂钩,python,google-app-engine,google-cloud-datastore,Python,Google App Engine,Google Cloud Datastore,我想创建一个合适的post_-create(也是post_-get和post_-put)钩子,类似于我的应用程序的DB版本 不幸的是,我不能使用has_complete_密钥 问题是众所周知的:模型中保存了缺少的数据 现在我已经这样实现了: class NdbStuff(HooksInterface): def __init__(self, *args, **kwds): super(NdbStuff, self).__init__(*args, **kwds)

我想创建一个合适的post_-create(也是post_-get和post_-put)钩子,类似于我的应用程序的DB版本

不幸的是,我不能使用has_complete_密钥

问题是众所周知的:模型中保存了缺少的数据

现在我已经这样实现了:

class NdbStuff(HooksInterface):

    def __init__(self, *args, **kwds):
        super(NdbStuff, self).__init__(*args, **kwds)
        self._is_saved = False

    def _put_async(self, post_hooks=True, **ctx_options):
        """ Implementation of pre/post create hooks. """

        if not self._is_saved:
            self._pre_create_hook()

        fut = super(NdbStuff, self)._put_async(**ctx_options)

        if not self._is_saved:
            fut._immediate_callbacks.insert(
                0,
                (
                    self._post_create_hook,
                    [fut],
                    {},
                )
            )
            self._is_saved = True

        if post_hooks is False:
            fut._immediate_callbacks = []

        return fut

    put_async = _put_async

    @classmethod
    def _post_get_hook(cls, key, future):
        obj = future.get_result()

        if obj is not None:
            obj._is_saved = True

        cls._post_get(key, future)

    def _post_put_hook(self, future):
        if future.state == future.FINISHING:
            self._is_saved = True
        else:
            self._is_saved = False
        self._post_put(future)
除了post_create钩子之外的所有东西似乎都起作用了

每次使用put\u async而不首先检索对象时,都会触发post\u create


如果您能给我一点提示,告诉我如何在创建对象后只触发一次post_create_钩子,我将不胜感激。

我不知道您为什么要创建NDBStuff类

如果您创建了一个类的实例,并且希望跟踪
\u是否已保存
或类似的内容,请使用工厂来控制属性的创建和设置,在这种情况下,跟踪\u是否新更为合理

class MyModel(ndb.Model):

    some_prop = ndb.StringProperty()

    def _pre_put_hook(self):

        if getattr(self,'_is_new',None):
           self._pre_create_hook()
        # do something

    def _pre_create_hook(self):
        # do something on first save
        log.info("First put for this object")

    def _post_create_hook(self, future):
        # do something

    def _post_put_hook(self, future);
        if getattr(self,'_is_new', None):
           self._post_create_hook(future) 
           # Get rid of the flag on successful put, 
           # in case you make some changes and save again.
           delattr(self,'_is_new')

    @classmethod
    def factory(cls,*args,**kwargs):
        new_obj = cls(*args,**kwargs)
        settattr(new_obj,'_is_new',True)
        return new_obj
然后

将在第一次放置时调用_pre_create_hook,而不是在第二次放置时调用

始终通过工厂创建实体,然后始终执行对_pre_create_hook的调用


这有意义吗?

为什么不使用工厂来创建实体,并在创建对象时将
\u is\u saved
显式设置为false。在你开始放球之前。那么你就不必尝试使用init方法了。@TimHoffman,你能说得更具体一点吗?我在init中和类声明之后保存了_is_集,这些解决方案中的任何一个都不起作用。当put_async从2011年开始进行相关讨论时,is_saved只是没有更新为True:NDBStuff只是一个示例,它应该是其他NDB类的基类。它的构建,除其他外,使post_创建在执行put_异步时成为可能。我考虑了一个类似于您的解决方案,但它需要在流和对象创建方面进行大量更改。这与初始化对象时添加标志基本相同,即foo=MyModel(**args,is_new=True)。此外,我担心post_put可能无法清除标志,因为它会运行,而不管是否失败。总而言之:我只是想在我所有的ndb类中添加一个漂亮干净的post_create。重写init等可能充满危险,除非你仔细计划。我刚刚通读了该线程,guido的建议是从_pb重写
,并设置标志以指示它不是刚刚创建的。他还提到使用工厂。您也可以使用_post_get_hook执行同样的操作,设置一个标志-
not_new
,并反转检查,以便仅在检索对象时才设置它。从\u pb
重写像
\u这样的私有方法似乎有点风险。我正在考虑对
查询做类似的事情
-你对此有何看法?如果查询选项不起作用,我想我可以使用工厂。关于
\u post\u get\u hook
-看起来它在查询后不会被触发,所以我认为它不会解决问题。
    myobj = MyModel.factory(someargs)
    myobj.put()
    myobj.some_prop = 'test'
    myobj.put()