Reputation: 16298
I am trying to create something like a folder structure for saving to GAE ndb datastore. I will be saving a top root folder (MjlistitemFolder) to the datastore. A MjlistitemFolder can have a number of other subitems (Mjlistitem) in its items property. Ultimately the content of a folder items will be one of these: MjlistitemFolder, MjlistitemJobGeneric, MjlistitemJobApp
This all works if I create this structure in memory. But after put()ing it away and reloading the root folder from the datastore, I don't get the same structure back.
class Mjlistitem(ndb.Model):
pass
class MjlistitemFolder(Mjlistitem):
title = ndb.StringProperty()
items = ndb.StructuredProperty(Mjlistitem, repeated=True)
class MjlistitemJob(Mjlistitem):
pass
class MjlistitemJobGeneric(MjlistitemJob):
jobtype = ndb.IntegerProperty()
class MjlistitemJobApp(MjlistitemJob):
appleid = ndb.StringProperty()
I get these warnings:
WARNING 2014-04-04 07:14:17,506 model.py:2359] Skipping unknown structured subproperty (items.items.appleid) in repeated structured property (items of MjlistitemFolder)
WARNING 2014-04-04 07:14:17,506 model.py:2359] Skipping unknown structured subproperty (items.items.jobtype) in repeated structured property (items of MjlistitemFolder)
WARNING 2014-04-04 07:14:17,506 model.py:2359] Skipping unknown structured subproperty (items.items.appleid) in repeated structured property (items of MjlistitemFolder)
It seems like the db→instance process renders the stuff in items to be of Mjlistitem class only. How do I make them appear as their real inherited classes?
This is how I create a test structure:
rootfolder = MjlistitemFolder(title="root")
subfolder = MjlistitemFolder(title="Cool things")
subfolder.items.append(MjlistitemJobApp(appleid="281796108")) # evernote
subfolder.items.append(MjlistitemJobGeneric(jobtype=3)) # phone number
subfolder.items.append(MjlistitemJobApp(appleid="327630330")) # dropbox
rootfolder.items.append(MjlistitemJobGeneric(jobtype=15)) # passbook
rootfolder.items.append(subfolder)
rootfolder.items.append(MjlistitemJobGeneric(jobtype=17)) # appstore
rootfolder.put()
Upvotes: 1
Views: 183
Reputation: 6617
Polymodel
with repeated KeyProperty
The StructuredProperty
need to be changed to KeyProperty
because:
TypeError: This StructuredProperty cannot use repeated=True because its model class (Mjlistitem) contains repeated properties (directly or indirectly).
The Model
from google.appengine.ext import ndb
from google.appengine.ext.ndb import polymodel
class Mjlistitem(polymodel.PolyModel):
pass
class MjlistitemFolder(Mjlistitem):
title = ndb.StringProperty()
# StructuredProperty won't allow you to apply on nested model, use key property instead
items = ndb.KeyProperty(kind=Mjlistitem, repeated=True)
class MjlistitemJob(Mjlistitem):
pass
class MjlistitemJobGeneric(MjlistitemJob):
jobtype = ndb.IntegerProperty()
class MjlistitemJobApp(MjlistitemJob):
appleid = ndb.StringProperty()
The Usage
def test():
rootfolder = MjlistitemFolder(title="root")
subfolder = MjlistitemFolder(title="Cool things")
subfolder.items.append(MjlistitemJobApp(appleid="281796108").put()) # evernote
subfolder.items.append(MjlistitemJobGeneric(jobtype=3).put()) # phone number
subfolder.items.append(MjlistitemJobApp(appleid="327630330").put()) # dropbox
rootfolder.items.append(MjlistitemJobGeneric(jobtype=15).put()) # passbook
rootfolder.items.append(subfolder.put())
rootfolder.items.append(MjlistitemJobGeneric(jobtype=17).put()) # appstore
rootfolder.put()
the repeated property won't perform well if there are too many items in one folder, so it would be better if
class Mjlistitem(polymodel.PolyModel):
parent = ndb.KeyProperty(kind="Mjlistitem")
def set_parent(self, parent):
assert isinstance(parent, MjlistitemFolder)
self.parent = parent.key
class MjlistitemFolder(Mjlistitem):
title = ndb.StringProperty()
class MjlistitemJob(Mjlistitem):
pass
class MjlistitemJobGeneric(MjlistitemJob):
jobtype = ndb.IntegerProperty()
class MjlistitemJobApp(MjlistitemJob):
appleid = ndb.StringProperty()
The Usage
def test():
rootfolder = MjlistitemFolder(title="root")
rootfolder.put()
subfolder = MjlistitemFolder(title="Cool things")
subfolder.set_parent(rootfolder)
subfolder.put()
a = MjlistitemJobApp(appleid="281796108")
a.set_parent(subfolder)
a.put()
b = MjlistitemJobGeneric(jobtype=3)
b.set_parent(subfolder)
b.put()
c = MjlistitemJobApp(appleid="327630330")
c.set_parent(subfolder)
c.put()
Upvotes: 1