2014-01-18 60 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()