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

Why does my use of NDB's `populate()` not accept `id` or `parent`, but only `key`?

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

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

You cannot easily define a property named "key", "id", "parent", or "namespace". If you pass, for example, key="foo" in a constructor or populate() call, it sets the entity's key, not a property attribute named "key".

对于populate(),它说它将接受与构造函数相同的关键字参数。但是,似乎我做错了什么,因为唯一有效的关键字参数是 key。使用 id and/or 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 一起使用的效果,但我想知道我在这里缺少什么。

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

这个看源码就清楚了,比如this line模型构造函数:

Note: you cannot define a property named key; the .key attribute always refers to the entity's key. But you can define properties named id or parent. Values for the latter cannot be passed through the constructor, but can be assigned to entity attributes after the entity has been created.

建议我们可以将 idparent 用作 properties/attributes,因此 populate 调用将尝试设置它们。

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

Each keyword argument will be used to set a corresponding property. Keywords must refer to valid property name. This is similar to passing keyword arguments to the Model constructor, except that no provisions for key, id or parent are made.

也许应该用这些信息更新文档以避免混淆。我自己从来没有 运行 进入这个问题,也许是因为我一直在遵循 "only setting the key when instantiating a model" 的建议,但是我找不到这个声明的引用;我把它作为一个经验法则,我的印象是之后尝试分配它应该会在任何地方引发异常。

好像前面的引用还不够,看看构造函数中的this line

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

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

当使用祖先路径时,

parentKey 的 属性。构造函数接受它是为了方便,但由于它不是它自己的 属性,populate() 会抱怨它不存在。 id 也是如此。构造函数使用 id 使用 _get_kind()id.

的值构造一个 Key

一个例子值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'