在App Engine中使用数据存储区实体时,如果您选择保留该实体的引用,则在对实体执行put操作后,人们会注意到奇怪的行为。
例如,请参阅this issue,其中重复的String属性在执行put之后变为_BaseValue。
在随后的讨论中,关于重复的字符串属性,Guido van Rossum写道:
“我明白了。我们应该记录你不应该挂起来 列入项目列表的时间太长;有各种形式的 围绕那个未定义的行为。“
我从这个帖子中得到的结论是,在put之后长时间保持对实体的引用并不是一个好主意,因为可能会出现意外行为。
但是,当我查看Model.get_or_insert()
方法的GAE source code时,我看到以下代码(已删除docstring):
@classmethod
def get_or_insert(cls, key_name, **kwds):
def txn():
entity = cls.get_by_key_name(key_name, parent=kwds.get('parent'))
if entity is None:
entity = cls(key_name=key_name, **kwds)
entity.put()
return entity
return run_in_transaction(txn)
注意如何执行put操作,并在post-put后返回实体。就在上面,我们看到了一个不推荐这个的例子。
任何人都可以澄清何时何时不能保持对实体的引用,post put? Guido似乎暗示有各种各样的情况,这可能是一个坏主意。只是好奇是否有人看过这方面的文件(我找不到)。
谢谢!
答案 0 :(得分:1)
问题中描述的问题不是关于实体,而是关于从其属性获得的列表。只要您愿意,您可以持有实体的副本。它只是一个对象。
这个问题是由一些"魔法"引起的。功能由ndb提供。我们来看看模型定义
from google.appengine.ext.ndb import model
class MyModel(model.Model):
items = model.StringProperty(repeated=True)
我们可以对物品属性说些什么?
它看起来像一个类属性,但是模型的元类逻辑.Model将其转换为实例属性。
这些实例属性是什么类型的?
可以像字符串列表一样访问它们,但它们是更复杂的对象,具有从数据存储区存储和检索数据所需的逻辑,验证等。
这"魔法"在大多数情况下运作良好,但有时它并不适用。其中一个有问题的情况是当您从实例获取对项目的引用并尝试在调用put之后使用它。 Guido提到的另一个案例是传递外部列表以初始化items属性,然后尝试通过操作外部列表来修改此属性。
要记住的事情:ndb中的模型属性尝试表现得像它们的基本类型,但它们是更复杂的对象。您可以在Writing property subclasses
中详细了解其内部信息