I am leveraging NDBs ComputedProperty and an ancestor query to count another model's objects that match a particular filter. The ComputedProperty looks something like this:
class Goal(ndb.Model):
various_attributes = various_properties
@ndb.ComputedProperty
def count_active_actions(self):
return Action.query(ancestor=self.key).filter(
Action.status=='active').count()
class Action(ndb.Model):
status = ndb.StringProperty(choices=(
'not started', 'active', 'completed', 'on hold'))
various_attributes = various_properties
@ndb.ComputedProperty(
def count_active_tasks(self):
return Task.query(ancestor=self.key).filter(
Task.status=='active').count()
class Task(ndb.Model):
status = ndb.StringProperty(choices=(
'not started', 'active', 'completed', 'on hold'))
various_attributes = various_properties
When I create a Goal
object, I do not store anything as its parent. Notice that I have a similar ComputedProperty on Goal as I do on Action. I receive no errors when goal.put() is executed when writing a goal.
However when creating an action object, I store the parent as the goal.key
like this:
action = Action(parent=goal.key, various_other_properties = various_other_values)
action.put()
When the action is written, the ComputedProperty
query is being executed and given that the action has not been completely written, the id
for action has not been assigned and thus is None
.
The error I receive is:
BadValueError: Expected complete Key, got Key('Goal', '##########', 'Action', None)
The behavior makes sense given what I think is happening behind the scenes. However I am assuming that I am missing something or am approaching this problem incorrectly as this seems to me to be a common use case.
My desired goal is to have a property of a parent object represent the count of a child object that matches a certain criteria plus has the parent object's key as its ancestor.
Is there a better way to achieve this? or is there something obvious that I am missing?