为什么我使用NDB的`populate()`不接受`id`或`parent`,而只接受`key`?

时间:2015-10-15 11:40:00

标签: python google-app-engine app-engine-ndb google-cloud-datastore

我想创建一个实体对象,在构建之后,在将其写入数据存储区之前,我想设置父元素和id。

根据App Engine docs,构造函数接受以下关键字参数: - id - key - parent

  

您无法轻松定义名为" key"," id"," parent"或   "命名空间&#34 ;.例如,如果你通过了key =" foo"在构造函数或   populate()调用,它设置实体的键,而不是属性属性   命名为" key"。

对于populate(),它表示它将接受与构造函数相同的关键字参数。但是,我似乎做错了,因为唯一有效的关键字参数是key。使用id和/或parent会给我带来错误。

class Foo(ndb.Model):
    pass

foo = Foo()
foo.populate(key=ndb.Key('Bar', 1, 'Foo', 123))
foo.key == ndb.Key('Bar', 1, 'Foo', 123)  # True

相反,我使用关键字parent ...

f.populate(parent=ndb.Key('Bar', 1))

......我得到了这个追溯:

Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 2960, in _populate
    self._set_attributes(kwds)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 2970, in _set_attributes
    prop = getattr(cls, name)  # Raises AttributeError for unknown properties.
AttributeError: type object 'Foo' has no attribute 'parent'

或有时候(不确定是什么产生了影响):

File "<console>", line 1, in <module>
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 2960, in _populate
    self._set_attributes(kwds)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 2972, in _set_attributes
    raise TypeError('Cannot set non-property %s' % name)
TypeError: Cannot set non-property parent

如果我使用id ...

f.populate(id=123)

我再次出现属性错误:

Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 2960, in _populate
    self._set_attributes(kwds)
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 2970, in _set_attributes
    prop = getattr(cls, name)  # Raises AttributeError for unknown properties.
AttributeError: type object 'Foo' has no attribute 'id'

上面我的所有populate()示例都不应该使用任何关键字参数吗?

我知道,我只能使用key来实现与parentid相同的功能,但我想知道我在这里缺少的内容。< / p>

2 个答案:

答案 0 :(得分:3)

使用祖先路径时,

parentKey的属性。构造函数接受它是为了方便,但由于它不是它自己的属性,populate()会抱怨它不存在。同样适用于id。构造函数使用id使用Key_get_kind()的值构建id

一个例子值得1000条评论。了解idparent如何用于构建key

>>> from google.appengine.ext import ndb
>>>>
>>> class Foo(ndb.Model):
...     pass
...
>>> foo = Foo(id=123, parent=ndb.Key('Bar', 1))
>>> foo.key
Key('Bar', 1, 'Foo', 123)
>>> foo.id
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'id'
>>> foo.parent
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'parent'

答案 1 :(得分:2)

在这个问题上,文档可能不够清晰,但您只应使用populate来更新模型的属性(实际数据)。

这很清楚源代码,例如模型构造函数的this line

  

注意:您无法定义名为key的属性; .key属性始终引用实体的密钥。但您可以定义名为id或parent的属性。后者的值不能通过构造函数传递,但可以在创建实体后分配给实体属性。

建议我们可以使用idparent作为属性/属性,因此populate调用会尝试设置它们。

一旦我们到达populate implementation,它就会变得更加清晰,其中内联文档中有一个针对您的确切问题的规定:

  

每个关键字参数将用于设置相应的属性。关键字必须引用有效的属性名称。这类似于将关键字参数传递给Model构造函数,除了没有为key,id或parent做出规定。

也许应该使用此信息更新文档以避免混淆。我自己从来没有遇到过这个问题,也许是因为我一直遵循“仅在实例化模型时设置密钥”的建议,但是我找不到这个声明的引用;我认为这是一个经验法则,我认为之后尝试分配它应该会引起各地的例外。

如果之前的引用不够,请查看构造函数中的this line

self._key = _validate_key(key, entity=self)

你不会在其他任何地方找到它,所以这是一个被正确分配给模型的键的唯一实例(你可以想象,populate只迭代并设置值)。