2014-01-18 37 views
0

在谷歌的云数据存储我的代码等价于:App Engine的嵌套实体列表

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() 

回答

1

不能直接使用Expando模型。您需要为重复的属性创建ndb.Expando的子类才能工作。

例如

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)] 
+0

你尝试保存到数据存储?我得到同样的例外。请参阅我的帖子的编辑以了解我使用过的代码。注意顺便说一句,在'foo.put()' –

+0

引发异常是的,你是正确的。我刚刚阅读了Expando课程的来源,我不相信你现在可以做到你想做的。目前,如果属性是Model(即结构化)属性,它将创建一个StructuredProperty,如果它是一个列表,它将它包装在GenericProperty中,但嵌套Expando似乎没有处理。尽管你可以在StructuredProperty中重复一个Expando。 –

+0

在这个问题上看到它的一个例子http://stackoverflow.com/questions/13631884/ndb-querying-a-genericproperty-in-repeated-expando-structuredproperty –

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

+0

这是否反序列化到谷歌云数据存储中的'datastore.Entity'类?我的主要目标是让这两个代码库以相同的方式工作。 –

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()