Reputation: 2154
I have declared 2 ndb models as follows:
class Event(ndb.Model):
event_type = ndb.KeyProperty()
@property
def installments(self):
return EventInstallment.query().filter(EventInstallment.event == self.key).count()
class EventInstallment(ndb.Model):
event = ndb.KeyProperty()
I persist a single entity of type Event and another of type EventInstallment. EventInstallment.event is the Key of the declared Event entity. The following query works (i.e. returns 1) when run locally but not when deployed:
event_query = Event.query()
event_query = event_query.filter(ndb.GenericProperty('installments') > 0)
print event_query.count()
I have cleared memcache, and double checked that all properties of EventInstallment are correct. When opening the EventInstallment entity in datastoreviewer it has a hotlink to the Event key, as expected.
Can someone tell me what's going wrong here? Specifically I'm curious to know why this works locally and not when deployed.
Upvotes: 0
Views: 151
Reputation: 881555
The filter
must be able to run in the datastore, and, in a deployed app, filter(ndb.GenericProperty('installments') > 0)
clearly can't (the simulation dev_appserver
does is not 100% accurate, I bet its authors never dreamed of checking for something like that).
Rather, what you want is a ComputedProperty
, which is computed and actually sent to the datastore at put
time, allowing the datastore to perform searches on it. To wit:
class Event(ndb.Model):
event_type = ndb.KeyProperty()
@property
def _installments(self):
return EventInstallment.query().filter(EventInstallment.event == self.key).count()
installments = ndb.ComputedProperty(lambda self: self._installments)
Now, filter(Event.installments > 0)
will work -- as long as the number of related EventInstallment
entities at the time the Event
entity was last put
was positive. (The datastore won't re-run any code to update Event
entities when EventInstallment
entities are added, removed, or altered; ComputedProperty
is computed at put
time on the entity it belongs to, and it's computed on the appengine instance side of things, i.e in "application level code", just before the entity's sent to the datastore side of things).
You may want to work the other way 'round: query for EventInstallment
entities, making a set of their event
properties to remove duplicates, and using the len
of that set as your desired count. Yes, that requires fetching all of them, but counting is not much faster than fetching anyway.
Upvotes: 2