这似乎是一个常见的要求,它是内置的,但无论如何:如果您有一个像下面这样的模型,如何阻止 eggs
属性在设置后发生变异?
class Spam(ndb.Model):
eggs = ndb.StringProperty()
目标是让属性不是必需的,因此它默认为None
,但一旦它从None
发生变异,对于上述情况下的字符串,它永远不能再次更改,但任何有关定义不可变属性的见解将不胜感激。
我曾考虑过使用 ndb.Property
的 validator
参数来传入函数;请参阅下面的答案,了解为什么这在这里不起作用。它对于理解所涉及的对象和命名空间很有用。
最佳答案
一种不需要使用自定义属性的方法是使用 Hook ,请参阅文档 https://developers.google.com/appengine/docs/python/ndb/modelclass#Model__post_get_hook
您将使用 _post_get_hook(cls, key, future)
和 _pre_put_hook(self)
在_post_get_hook
中,您将存储属性的原始值
在 _pre_put_hook 中,您将检查它是否与原始值相同,除非原始值是 None
。
即
class Spam(ndb.Model):
eggs = ndb.StringProperty()
@classmethod
def _post_get_hook(cls,key,future):
obj = future.get_result()
obj._my_eggs_prop = obj.eggs
def _pre_put_hook(self):
if hasattr(self,'_my_eggs_prop'):
if self.eggs != self._my_eggs_prop:
if self._my_eggs_prop != None:
# do some logging.
raise ValueError
else:
setattr(self,'_my_eggs_prop',self.eggs)
# if the saved value doesn't exist, create it and store
# the value in case an update occurs after the initial put
# this also means the object was created and not get()
这是一个工作示例
s~lightning-catfish> import spam
s~lightning-catfish> x = spam.Spam(id='canned')
s~lightning-catfish> x.eggs = 'green'
s~lightning-catfish> x.put()
Key('Spam', 'canned')
s~lightning-catfish> y = x.key.get()
s~lightning-catfish> y._my_eggs_prop
u'green'
s~lightning-catfish> y.eggs = 'blue'
s~lightning-catfish> y.put()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 3232, in _put
return self._put_async(**ctx_options).get_result()
File "/home/timh/google_appengine/google/appengine/ext/ndb/model.py", line 3247, in _put_async
self._pre_put_hook()
File "spam.py", line 18, in _pre_put_hook
raise ValueError
ValueError
这种方法的缺点是您可以更改其中的属性依赖以获取一些额外的代码,然后只有在执行 put 时才发现它。然而,这可能并没有那么糟糕,因为理论上您不应该有任何代码在更改属性后对其进行修改。因此您想要记录并追踪这种情况是如何发生的。或者,您可以将该值重置为原始设置,但随后会保留不正确的代码。
自定义属性需要更多考虑;-)
关于google-app-engine - 在 App Engine 上,如何使 ndb 属性一旦设置就不可变?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20672561/