Brian M. Hunt
Brian M. Hunt

Reputation: 83778

Google App Engine get PolyModel as child class

When I run Google App Engine likeso:

 from google.appengine.ext import db
 from google.appengine.ext.db import polymodel

 class Father(polymodel.PolyModel):
      def hello(self):
          print "Father says hi"

 class Son(Father):
      def hello(self):
          print "Spawn says hi"

When I run, e.g.

 s = Son()
 s.put()

 son_from_father = Father.get_by_id(s.key().id())

 son_from_father.hello()

This prints "Father says hi". I would expect this to print "Son says hi". Does anyone know how to make this do what's expected, here?

EDIT:

The problem was, ultimately, that I was saving Spawn objects as Father objects. GAE was happy to do even though the Father objects (in my application) have fewer properties. GAE didn't complain because I (silently) removed any values not in Model.properties() from the data being saved.

I've fixed the improper type saving and added a check for extra values not being saved (which was helpfully a TODO comment right where that check should happen). The check I do for data when saving is basically:

def save_obj(obj, data, Model):
   for prop in Model.properties(): # checks/other things happen in this loop
      setattr(obj, prop, data.get(prop))

   extra_data = set(data).difference(Model.properties())
   if extra_data:
      logging.debug("Extra data!")

The posts here were helpful - thank you. GAE is working as expected, now that I'm using it as directed. :)

Upvotes: 0

Views: 783

Answers (2)

Alex Martelli
Alex Martelli

Reputation: 881555

I can't reproduce your problem -- indeed, your code just dies with an import error (PolyModel is not in module db) on my GAE (version 1.2.5). Once I've fixed things enough to let the code run...:

import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext.db import polymodel

class Father(polymodel.PolyModel):
    def hello(self):
        return "Father says hi"

class Son(Father):
    def hello(self):
        return "Spawn says hi"

class MainHandler(webapp.RequestHandler):

  def get(self):
    s = Son()
    s.put()
    son_from_father = Father.get_by_id(s.key().id())
    x = son_from_father.hello()
    self.response.out.write(x)

def main():
  application = webapp.WSGIApplication([('/', MainHandler)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main()

...I see "Spawn says hi" as expected. What App Engine release do you have? What happen if you use exactly the code I'm giving?

Upvotes: 1

NealWalters
NealWalters

Reputation: 18187

You did a "Father.get..." so you created an object from the Father class. So why wouldn't it say "Father says hi".

If you Father class had lastname and firstname, and your Son class had middle name, you won't get the middle name unless you specifically retrieve the 'Son' record.

If you want to do a polymorphic type query, here's one way to do it. I know it works with attributes, but haven't tried it with methods.

 fatherList = Father.all().fetch(1000) 
 counter = 0 
 #I'm using lower case father for object and upper case Father for your class...
 for father in fatherList:
     counter += 1 
     if isinstance(father,Son):
        self.response.out.write("display a Son field or do a Son method") 
     if isinstance(father,Daughter):
        self.response.out.write("display a Daughter field or do a Daughter method")

Neal Walters

Upvotes: -1

Related Questions