【问题标题】:Google App Engine NDB creating __metadata__ propertiesGoogle App Engine NDB 创建 __metadata__ 属性
【发布时间】:2017-01-11 01:05:41
【问题描述】:

我一直在使用 Google App Engine 开发原型库存应用程序。我最近从使用旧的 DB 数据存储库切换到使用新的 NDB 库,功能很酷,但是在对我的一个实体进行更改时,NDB 突然插入了一个名为“元数据”在我的实体中。这是实体描述(我所做的更改是添加“inv_posid”和“inv_lastchange”属性,没什么大不了的):

class Inventory(ndb.Model):
    inv_product = ndb.KeyProperty(kind = Product)
    inv_prdcr_name = ndb.StringProperty(default="")
    inv_product_type = ndb.StringProperty(default="")
    inv_product_name = ndb.StringProperty(default="")
    inv_product_year = ndb.IntegerProperty(default=0)
    inv_count = ndb.IntegerProperty(default=0)
    inv_price = ndb.IntegerProperty(default=0)
    inv_glass_price = ndb.IntegerProperty(default=0)
    inv_bin = ndb.StringProperty(default="")
    inv_posid = ndb.StringProperty(default="")
    inv_lastchange = ndb.FloatProperty(default=0.0)

通过添加新属性,我打算更改我的查询以使用“inv_lastchange”作为过滤器,并且由于 NDB 从不包含不包含适当属性的结果中的实体,我想运行快速扫描通过我的数据存储,将属性适当地添加到所有实体。所以,这就是我所做的:

...
@ndb.tasklet
def fixInventory(invitem):
    invitem.inv_posid = ""
    invitem.inv_lastchange = 0.0
    invkey = yield invitem.put_async()

inventory = Inventory.query()
output = inventory.map(fixInventory)

我认为使用 tasklet 并看看异步调用是如何工作的会很好。然而,在这样做之后,当我去查看数据存储查看器(在我的本地数据存储上)时,我看到了这个新的“metadata”属性,我只是假设它是 NDB 需要的,所以我什么都没想。

直到下一次我尝试更新我的库存物品之一时,我收到了这个错误:

  File "/Programming/VirtualCellar/server/virtsom.py", line 2118, in get
    inventory.put()
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/model.py", line 3432, in _put
    return self._put_async(**ctx_options).get_result()
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/tasklets.py", line 326, in get_result
    self.check_success()
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/tasklets.py", line 369, in _help_tasklet_along
    value = gen.throw(exc.__class__, exc, tb)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/context.py", line 810, in put
    key = yield self._put_batcher.add(entity, options)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/tasklets.py", line 369, in _help_tasklet_along
    value = gen.throw(exc.__class__, exc, tb)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/context.py", line 343, in _put_tasklet
    keys = yield self._conn.async_put(options, datastore_entities)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/ndb/tasklets.py", line 455, in _on_rpc_completion
    result = rpc.get_result()
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/api/apiproxy_stub_map.py", line 613, in get_result
    return self.__get_result_hook(self)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1882, in __put_hook
    self.check_rpc_success(rpc)
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1373, in check_rpc_success
    raise _ToDatastoreError(err)
BadRequestError: cannot store entity with reserved property name '__metadata__'

那么发生了什么?有什么我忘了做的吗?感觉“元数据”属性应该以某种方式隐藏或保护,但它已像常规属性一样添加,现在阻止对实体进行任何其他保存.有人遇到过这个吗?

【问题讨论】:

  • 我从未听说过ndb 自动创建metadata 属性。您确定该属性以前不存在吗?弹出此属性时,您究竟是如何更改实体的?

标签: google-app-engine app-engine-ndb


【解决方案1】:

__metadata__ 属性会在实体保存到数据存储区时添加到实体,并在从数据存储区读取时删除。这是在google/appengine/datastore/datastore_stub_util.py 中的_ToStorageEntity_FromStorageEntity 函数中完成的。

大概是内部故障以某种方式破坏了您的实体。

您可以通过从实体实例的 _properties 字典中删除 __metadata__ 属性并保存来恢复。

例如:

for inv in Inventory.query():
    del inv._properties['__metadata__']
    inv.put()

(也许在尝试之前备份您的本地数据存储文件,以防发生意外)。

【讨论】:

  • ndb 不允许以 _ 开头的属性,但 db 允许。您可以尝试使用db 进行修复。
  • @JeffO'Neill 我对过去曾遇到过这个问题有一个微弱的记忆,但我已经修复了它而不必下降到db,尽管我可能弄错了。希望 OP 会报告并让我们知道发生了什么。
【解决方案2】:

所以,根据上面 snakecharmerb 所说的,我开始查看为什么我的数据存储查看器也向我显示 __metadata__ 属性,结果发现我之前下载了旧版本的google app engine SDK,出于某种原因,我的环境变量仍然指向那个旧版本,即使我已经安装了几次最新版本的 SDK。我从我的机器上擦除了 google app engine SDK 的所有痕迹,并从头开始重新安装了 SDK,瞧! __metadata__ 属性在数据存储查看器和我自己的查看器中都消失了代码!我目前的假设是旧版本的 google/appengine/datastore/datastore_stub_util.py 文件没有以相同的方式处理 __metadata__ 属性。

非常感谢您的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-27
    • 2012-04-12
    • 1970-01-01
    相关资源
    最近更新 更多