Question

I am using Endpoints-proto-datastore created by Danny Hermes for Google App Engine.

My model looks something like this:

class Datum(EndpointsModel):
    year = ndb.IntegerProperty(required=True)
    value = ndb.FloatProperty(required=True)

class Variable(EndpointsModel):
    name = ndb.StringProperty(required=True)
    data = ndb.StructuredProperty(Datum, repeated=True)

class Indicator(EndpointsModel):
    name = ndb.StringProperty(required=True)
    variables = ndb.KeyProperty(kind=Variable, repeated=True)
    formula = ndb.StringProperty(required=True)

And my API is something like this:

@endpoints.api(name="SomeAPI", version="v1", description="someDescription")
class SomeAPI(remote.Service):
    @Indicator.query_method(query_fields=("limit", "pageToken"), 
                            name="indicator.list",
                            path="indicators")
    def list_indicators(self, query):
        return query

The problem is that when i make the request, i get

{
 "items": [
  {
   "name": "IndicatorName",
   "variables": [
    "agtkZXZ-bW9uaXRvcnITCxIIVmFyaWFibGUiBU1BVFJQDA",
    "agtkZXZ-bW9uaXRvcnISCxIIVmFyaWFibGUiBFBST1AM"
   ],
   "formula": "someFormula"
  }
 ]
}

But getting the variable keys is not really useful for me, because that would force the client to make another request for the variables on the indicator entity. I would like to get the variable content, like this:

{
 "items": [
  {
   "name": "IndicatorName",
   "variables": [
     {
      "name": "some Variable",
      "data": [
       {
        "value": 230,
        "year": 2000,
       },
       {
        "value": 250,
        "year": 2005,
       }
      ]
     },
     {
      "name": "some other Variable",
      "data": [
       {
        "value": 230,
        "year": 2000,
       },
       {
        "value": 250,
        "year": 2005,
       },
       {
        "value": 260,
        "year": 2010,
       }
      ]
     }
   ],
   "formula": "someFormula"
  }
 ]
}
Was it helpful?

Solution

You don't want a KeyProperty then. If you want to reference the other property use ndb.StructuredProperty:

class Indicator(EndpointsModel):
    name = ndb.StringProperty(required=True)
    variables = ndb.StructuredProperty(Variable, repeated=True)

In advanced cases like yours, where the referenced object may change, but the keys will not, you can use an EndpointsAliasProperty. For some point of reference, see the docs for some examples or some StackOverflow questions Using endpoints-proto-datastore, how do you pass attributes to a method that are not contained in the EndpointsModel or Cloud Endpoints - Retrieving a single entity from datastore (by a property other than the helper methods provided by EndpointsModel).

UPDATE: After more information about the classes was added, indicating a special need, I added the following:

For this specific case, you'd want to store the variables as some other name like variable_keys and then use variables to retrieve the values of the keys:

from endpoints_proto_datastore.ndb import EndpointsAliasProperty

class Indicator(EndpointsModel):
    name = ndb.StringProperty(required=True)
    variable_keys = ndb.KeyProperty(kind=Variable, repeated=True)
    formula = ndb.StringProperty(required=True)

and then as an instance method on Indicator define your getter (for variables) with no associated setter:

    @EndpointsAliasProperty(repeated=True, property_type=Variable.ProtoModel())
    def variables(self):
      return ndb.get_multi(self.variable_keys)

I would also advise setting _message_fields_schema on the Indicator class so this getter is only called when you want it, since the get_multi is an expensive RPC if you don't use it. Then when you want it in your query, you can include it in the collection_fields:

    @Indicator.query_method(query_fields=("limit", "pageToken"), 
                            collection_fields=("variables", ...),
                            name="indicator.list",
                            path="indicators")
    def list_indicators(self, query):
        return query

PS: Check out PEP8 - Whitespace in Expressions and Statements; "Don't use spaces around the = sign when used to indicate a keyword argument or a default parameter value."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top