Question

I'm trying to define a model whose id is case-insensitive but case-preserving, and the below nearly works:

class MyModel(endpoints_ndb.EndpointsModel):

    _message_fields_schema = ('id', 'name')

    caseful_id = ndb.StringProperty(indexed=False)
    name = ndb.StringProperty(required=True)

    def IdSet(self, value):
        if not isinstance(value, basestring):
            raise TypeError('ID must be a string.')
        self.caseful_id = value
        self.UpdateFromKey(ndb.Key(self.__class__, value.lower()))

    @endpoints_ndb.EndpointsAliasProperty(setter=IdSet)
    def id(self):
        return self.caseful_id

Creating a new instance stores the id in lowercase, with the original capitalisation in caseful_id, and fetching a list returns the original capitalisations, but requesting a specific model by id with:

@MyModel.method(request_fields=('id',), path='mymodel/{id}',
                http_method='GET', name='mymodel.get')
def MyModelGet(self, mymodel):
    if not mymodel.from_datastore:
        raise endpoints.NotFoundException('MyModel not found.')
    return mymodel

always returns the same id that was given in the request, with the same capitalisation. Is there a way to make it actually call the id getter function?

Was it helpful?

Solution

Your setter is being called, and it is causing the behavior you don't want. Tearing it down:

def IdSet(self, value):
    if not isinstance(value, basestring):
        raise TypeError('ID must be a string.')
    self.caseful_id = value
    self.UpdateFromKey(ndb.Key(self.__class__, value.lower()))

since you call

self.caseful_id = value

before UpdateFromKey, the caseful_id will always be the one from the most recent request.

Bear in mind that UpdateFromKey tries to retrieve an entity by that key and then patches in any missing data from the entity stored in the datastore (and also sets from_datastore to True).

Since you set the caseful_id field before UpdateFromKey, there is no missing data. Instead, you could do this to set the value if not already set (and so this wouldn't be relevant for your 'GET' method):

def IdSet(self, value):
    if not isinstance(value, basestring):
        raise TypeError('ID must be a string.')
    self.UpdateFromKey(ndb.Key(self.__class__, value.lower()))
    if self.caseful_id is None:
        self.caseful_id = value
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top