这似乎是一个普通的要求,它是内置的,但无论如何:如果你有一个类似下面的模型,你如何阻止eggs
属性在被设置后被变异?
class Spam(ndb.Model):
eggs = ndb.StringProperty()
目标是要求属性不,因此默认为None
,但一旦从None
变异,就会变为在上面的情况下,它永远不会再被改变,但是对于定义不可变属性的任何见解都将受到赞赏。
我曾考虑使用validator
的{{1}}参数传递函数;请参阅下面的答案,了解为什么在这里不起作用。它对于理解所涉及的对象和命名空间很有用。
答案 0 :(得分:2)
一种不要求您使用自定义属性的方法是使用钩子请参阅文档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时才发现它。然而,这可能不是那么糟糕,因为理论上你应该没有任何代码在改变后修改属性。所以你想记录,并追踪它是如何发生的。或者,您可以将值重置为原始设置,但随后会保留错误的代码。
自定义属性需要更多考虑; - )
答案 1 :(得分:1)
不幸的是,你无法用验证器做你想做的事。
(prop,value)
是要设置的属性实例和值。您在类的实例的验证器中没有句柄,因此没有预先存在的值。获取现有值所需的属性的所有方法都需要一个模型实例作为参数 - 比如_has_value。文档
将使用参数(prop,value)调用,并且应该返回 (可能是强制的)值或引发异常。打电话给 再次对强制值起作用不应该进一步修改该值。 (例如,返回value.strip()或value.lower()很好,但是 不值+'$'。)也可以返回None,这意味着“没有变化”。看到 还写属性子类 `https://developers.google.com/appengine/docs/python/ndb/properties#options
您需要编写自定义属性来管理值的状态并防止一旦设置覆盖。
请参阅下面的示例,向您显示您无法访问该属性的预先存在的值,并且未传递验证程序或具有该值的模型实例。
s~lightning-catfish> from pdb import set_trace
s~lightning-catfish> def valid(prop,val):
... set_trace()
... return val
...
s~lightning-catfish> class X(ndb.Model):
... x = ndb.StringProperty(validator=valid)
...
s~lightning-catfish> y = X(x="abc")
> <console>(3)valid()
(Pdb) p prop
StringProperty('x', validator=<function valid at 0xaf2d02c>)
(Pdb) p prop._has_value
<bound method StringProperty._has_value of StringProperty('x', validator=<function valid at 0xaf2d02c>)>
(Pdb) p prop._has_value()
*** TypeError: TypeError('_has_value() takes at least 2 arguments (1 given)',)
(Pdb) c
s~lightning-catfish> y
X(x='abc')