App Engine嵌套实体列表

时间:2014-01-18 20:28:18

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

在Google云数据存储区中,我的代码与此相同:

req = datastore.CommitRequest()
req.mode = datastore.CommitRequest.NON_TRANSACTIONAL
foo = req.mutation.insert_auto_id.add()

barListProperty = foo.property.add()
barListValue = []
for i in range(5):
    ent = datastore.Entity()
    a = ent.property.add()
    set_property(a, 'a', 1)
    b = ent.property.add()
    set_property(b, 'b', i)

set_property(barListProperty, 'barlist', barListValue)

key = datastore.Key()
path_element = key.path_element.add()
path_element.kind = 'Foo'

foo.key.CopyFrom(key)
print datastore.commit(req)

现在我想在NDB中构建相同的东西,所以我写了这个:

class Foo(Expando):
    pass

foo = Foo()
foo.barlist = [Expando(a=1, b=i) for i in range(5)]
foo.put()

但是我收到以下错误:

File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 570, in dispatch
    return method(*args, **kwargs)
  File "/base/data/home/apps/s~detect-analyze-notify-01a/sjuul.373145649709860280/main.py", line 317, in get
    foo.put()
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 3339, in _put
    return self._put_async(**ctx_options).get_result()
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 325, in get_result
    self.check_success()
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 368, in _help_tasklet_along
    value = gen.throw(exc.__class__, exc, tb)
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/context.py", line 748, in put
    key = yield self._put_batcher.add(entity, options)
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 368, in _help_tasklet_along
    value = gen.throw(exc.__class__, exc, tb)
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/context.py", line 280, in _put_tasklet
    keys = yield self._conn.async_put(options, datastore_entities)
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 454, in _on_rpc_completion
    result = rpc.get_result()
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 612, in get_result
    return self.__get_result_hook(self)
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1818, in __put_hook
    self.check_rpc_success(rpc)
  File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1333, in check_rpc_success
    raise _ToDatastoreError(err)
BadRequestError: BLOB, ENITY_PROTO or TEXT properties must be in a raw_property field.

我应该怎么做?

编辑:这不起作用

    class Foo(Expando):
        pass

    class Bar(Expando):
        pass

    foo = Foo()
    foo.barlist=[Bar(a=1, b=i) for i in range(5)]
    foo.put()

3 个答案:

答案 0 :(得分:1)

您无法直接使用Expando模型。您将需要为重复属性创建一个ndb.Expando的子类,以使其工作。

e.g。

s~lightning-catfish> class X(ndb.Expando):
...    pass

s~lightning-catfish> class Repeated(ndb.Expando):
...    pass
... 
s~lightning-catfish> z = X()
s~lightning-catfish> z.y = [Repeated(a=1,b=i) for i in range(5)]
s~lightning-catfish> z.y
[Repeated(a=1, b=0), Repeated(a=1, b=1), Repeated(a=1, b=2), Repeated(a=1, b=3), Repeated(a=1, b=4)]

答案 1 :(得分:0)

在我看来,你正在尝试保存一个本身尚未保留的实体,这留下了几个选项:

1)如果你想将Entity存储为一个单独的“行”,你可以保存它,然后存储一个键列表:

class Entity(db.Expando):
  pass

# Create your main entity.
e = Entity()
e.other_entities = []

# Create a bunch of others.
for i in range(5):
  other_entity = Entity(a=i, b=i+1)
  other_entity.put()
  # Attach the key to the main entity.
  e.other_entities.append(other_entity.key())

# Save your main entity.
e.put()

2)如果您想要Entity存储“内联”,您可以使用db.EmbeddedEntity type

class Entity(db.Expando):
  pass

# Create your main entity.
e = Entity()
e.other_entities = []

# Create a bunch of others (but don't save them).
for i in range(5):
  other_entity = Entity(a=i, b=i+1)
  # Append it to the list as an EmbeddedEntity
  e.other_entities.append(db.EmbeddedEntity(other_entity))

# Save your main entity.
e.put()

这样的一个示例是在the main Expando documentation page上,他们使用db.Text('Text value')来指定它应该存储为TextProperty而不是StringProperty

答案 2 :(得分:0)

一个好的选择是为列表设置一个新实体。因此,您可以根据需要插入任意数量的项目,作为“列表实体”的实例,您可以将其他实体设置为父项。

而不是这个(或类似的):

foo = Foo()
foo.barlist=[Bar(a=1, b=i) for i in range(5)]
foo.put()
你可以试试这个:

foo = ListFoo(parent= Foo)
foo.item = 'list item'
foo.put()