Reputation: 32061
I'm using NDB and an Expando model called MBObject because I'm creating objects dynamically with no fixed scheme. I create objects from dictionaries:
dic = {"groupName" : "my group",
"members" : [{"memberId" : "1"}, {"memberId" : "2"}]}
So what I want to do is create a group object that has a property called members, where members is a LocalStructuredProperty of MBObjects. (All objects are MBObject's, subclass of ndb.Expando)
However, there doesn't seem to be a way to specify the second part dynamically, and I'm getting errors:
def config_obj_from_dic(dictionary):
object = MBObject()
for key, value in dictionary.iteritems():
if isinstance(value, list):
objects = list()
for dic in value:
objects.append(config_obj_from_dic(dic))
value = objects
setattr(object, key, value)
return object
So basically I end up with a list of members, and attempt to set that as a property of the object, and hope that it automatically realizes I want a repeated LocalStructuredProperty. So obviously I see where the problem is, that it's not smart enough to handle that by itself. The question is, how would I make it handle that?
And if it won't work with a LocalStructuredProperty, then I'm also fine with using an ndb.JsonProperty, but it's still the same problem: how do I dynamically tell it that I want this to be a property of a certain type?
tl;dr: If I have an Expando model, and I do setattr(object, key, a_list)
, where I set a property as a list, how can I make it know that I want a LocalStructuredProperty
or a JsonProperty
, because now it doesn't know what to do with that list.
Upvotes: 2
Views: 1139
Reputation: 3570
This issue may be realted: http://code.google.com/p/appengine-ndb-experiment/issues/detail?id=216
The fix will be in the next release of the AppEngine SDK. Looks like you'd do this by first storing Expando models inside the Expando model (taken from the issues page):
def test_expando_in_expando_with_lists(self):
"""Passes"""
class B(ndb.Expando):
pass
class A(ndb.Expando):
pass
a = A(a1 = [B(b1 = [0,1,2,3]),B(b2='b2test')])
new_a = A(**a.to_dict())
self.assertEqual(a, new_a)
I would take a look at the structure of a.to_dict()
in the example above and verify how the dictionary object looks in comparison to your own. Also, I believe this will make a StructuredProperty, not a LocalStructuredProperty.
If you can pre-define the property type, this issue fixed a similar bug: http://code.google.com/p/appengine-ndb-experiment/issues/detail?id=207
Upvotes: 2
Reputation: 16882
The NDB expando model uses GenericProperty to set data, which only supports the following types: int, long, float, bool, str, unicode, datetime, Key, BlobKey, GeoPt, User, None.
To solve this problem: if you know all the properties and names of members
, then you can use an expando model with predefined properties (described in the docs) as LocalStructuredProperty
. However, if you don't know this (which would make sense since you're using expando), then the best options may be to serialize these members to JSON manually and save them in an expando property as a string.
Upvotes: 2