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())
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 ...>