0

I am using the Google App Engine polymodel to model data that can have more than one instance of a property - e.g. a contact could have multiple phone numbers. Say this is my setup:

class Foo(polymodel.PolyModel):
    some_prop = ndb.StringProperty()

    @property
    def bar(self):
        return Bar.query(Bar.foo == self.key)

class Bar(ndb.Model):
    foo = ndb.KeyProperty(kind = Foo)
    other_prop= ndb.StringProperty()

(I got this approach after reading this GAE article on data modeling: https://developers.google.com/appengine/articles/modeling)

Now when I do:

Foo._properties

I only get access to the following:

{'some_prop': StringProperty('some_prop'), 
 'class': _ClassKeyProperty('class', repeated=True)}

Is there any way to access to ALL properties, including those defined with "@property"?

Many thanks for any help or or insight on where I'm going wrong. - Lee

UPDATE: Based on @FastTurle's great answer, I've now added a class method that returns both class properties as well as methods tagged as properties via @property:

def props(self):
    return dict(self._properties.items() +  \
                   {attr_name:getattr(self,attr_name) for \
                    attr_name, attr_value in \
                    Foo.__dict__.iteritems() if \
                    isinstance(attr_value,property)}.items())
pixelphantom
  • 531
  • 1
  • 5
  • 16

1 Answers1

2

Performing Foo._properties should get you access to any attributes you define on your polymodel.PolyModel that inherit from google.appengine.ext.db.Property.

This means that KeyProperty, StringProperty, etc... will show up in Foo._properties, so I'm assuming you now need to find all the methods decorated by property.

Fortunately, this isn't that hard. First, a quick sidetrack into decorators (forgive me if you know this already).

In python decorators are just syntactic sugar. For example, these two methods result in the same thing:

@property
def bar(self):
    pass

def bar(self):
    pass
bar = property(bar)

Fortunately for us, property(obj) returns a new property object. This also means that @property returns a property object as well. You can kind of think of property as a class! And finally can use isinstance(bar, property) to see if bar is a property.

Finally, we can put this into use by examining each of Foo's attributes and selecting only those that are property instances.

for attr_name, attr_value in Foo.__dict__.iteritems():
    if isinstance(attr_value, property):
        print attr_name, attr_value

# bar, <property object at ...>
FastTurtle
  • 2,301
  • 19
  • 19
  • FastTurtle: wow, was not expecting this high-quality level response so quick: thanks so much! My code is now looking much nicer + I learned more about decorators. I've edited my answer to show the class method I added to return both properties and methods that are property objs. Hopefully that makes sense. Many thanks for your help here, greatly appreciated! :) – pixelphantom Aug 16 '13 at 20:01
  • @pixelphantom Glad to hear that my answer was helpful! The method you added looks good and hopefully does what you want. Good luck :) – FastTurtle Aug 16 '13 at 23:16