Python 谷歌应用引擎NDB post_创建挂钩
我想创建一个合适的post_-create(也是post_-get和post_-put)钩子,类似于我的应用程序的DB版本 不幸的是,我不能使用has_complete_密钥 问题是众所周知的:模型中保存了缺少的数据 现在我已经这样实现了: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)
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()