gsinha
gsinha

Reputation: 1185

How to to get Property Types of a NDB Model in GAE Python

[Added Solution at the end of question]

How to to get Property Types of a NDB Model in GAE Python ?

Example model :

class X(ndb.Model): 
    prop_1 = ndb.IntegerProperty ("a", indexed=True) 
    prop_2 = ndb.StringProperty ("b") 
    prop_3 = ndb.DateTimeProperty ("c", repeated=True) 
    prop_4 = ndb.DateProperty ("d", repeated=False)

Using GAE Metadata API did not help.

I can get list of all properties of model X using get_properties_of_kind(kind).

But get_representations_of_kind(kind) would not help me get the property types as it has the same property representation values for more than one property type ( like DateTime and Date both have INT64 ).

ATTEMPT 1

y = globals()["X"]  # IF I GET THE MODEL NAME AS STRING; ELSE y = X. 
logging.info (y) 
logging.info (vars(y)) 
for item in vars(y): 
    if (item[0]!="_"):  # ASSUMING ALL INTERNAL KEY NAMES START WITH "_". 
        logging.info ("item=["+item+"] ") 
        logging.info ("vars(y)[item]=["+repr (vars(y)[item])+"] ")

OUTPUT

2015-03-02 00:08:43.166 +0530 I X<prop_1=IntegerProperty('a'), prop_2=StringProperty('b'), prop_3=DateTimeProperty('c', repeated=True)>
2015-03-02 00:08:43.171 +0530 I {'__module__': '__main__', 'prop_1': IntegerProperty('a'), 'prop_2': StringProperty('b'), 'prop_3': DateTimeProperty('c', repeated=True), '_properties': {'a': IntegerProperty('a'), 'c': DateTimeProperty('c', repeated=True), 'b': StringProperty('b')}, '_has_repeated': True, '__doc__': None} 
2015-03-02 00:08:43.186 +0530 I item=[prop_1]
2015-03-02 00:08:43.191 +0530 I vars(y)[item]=[IntegerProperty('a')]
2015-03-02 00:08:43.195 +0530 I item=[prop_2]
2015-03-02 00:08:43.200 +0530 I vars(y)[item]=[StringProperty('b')]
2015-03-02 00:08:43.204 +0530 I item=[prop_3]
2015-03-02 00:08:43.209 +0530 I vars(y)[item]=[DateTimeProperty('c', repeated=True)]

Using this approach, I would get the Property Types of a Model as String ( like, DateTimeProperty('c', repeated=True) ). I would have to extract the Property Type ( DateTimeProperty ) using regex.

Is this the correct ( and the best ) way to do it ?

SOLUTION
Based on answers by @Greg and @Alex Martelli, I was able to come up with a solution :

obj = globals ()["X"] 
for item in obj._properties: 
    logging.info ("b item=["+item+"] ") 
    # This gave the short names of properties :  "a", "b", "c", .. 

    logging.info ("b needed part = ["+obj._properties[item].__class__.__name__+"] ") 
    # This gave the property type class :  "IntegerProperty", "StringProperty", "DateTimeProperty", .. 

for item in obj.__dict__: 
    if (item[0]!="_"): 
        logging.info ("HB item=["+item+"] ") 
        # This gave the actual property name :  "prop_1", "prop_2", "prop_3", ..  

Note that I could not use the GAE Metadata API since it needs at least one entity of the Model to be present, which is not necessary in my case.
In my situation, I need to create the class name from string ( hence the globals().. ).

Only problem, now, is how to correlate actual property names ( like "prop_1" ) to the obtained property types ? Right now, the short names ( like "a" ) map to property types.

Please let me know if I am doing something wrong.

Upvotes: 0

Views: 1181

Answers (2)

Alex Martelli
Alex Martelli

Reputation: 881675

If any entity of model class X exists, I would recommend:

from google.appengine.ext.ndb import metadata

props = metadata.get_properties_of_kind('X')
prop_to_type = {}
for p in props:
    prop_to_type[p] = type(getattr(X, p))

If no entity of model class X exists, props will be the empty list, so you may have to resort to slightly trickier approaches such as

props = X._property

In this case, props is a dict, and its values are instances of property classes -- but you can still loop on props (getting the dict's keys, which are the property names) and use the same type(getattr(... code as above to get the actual types.

I nevertheless consider this "slightly trickier" because in Python it's generally considered better to avoid accessing names that start with an underscore, when feasible!-)

Upvotes: 3

Greg
Greg

Reputation: 10360

If you have a model class, then its _properties attribute will contain the attributes that are datastore-properties. From there, you can access the __name__ of the class and/or any other attributes of the Property.

You don't need to be accessing globals() or vars() like you're doing, and there's definitely no need to resort to regex.

Upvotes: 2

Related Questions