问题
How can I set a parent/ancestor for an EndpointsModel and have the entity ID/Key generated automatically by datastore?
I've tried to adapt the keys_with_ancestors sample but seem to be hitting a bit of a block because it requires both id and parent to be specified. I'd like to do something similar except provide only parent id or key and have entity id/key auto-generated by the app engine datastore.
This following shows how I would do it using just NDB.
class Parent(ndb.Model):
name = ndb.StringProperty()
class MyModel(ndb.Model):
attr1 = ndb.StringProperty()
attr2 = ndb.StringProperty()
p = Parent(name="Jerry")
p_key = p.put() # or retrieve the key from somewhere else
mod = MyModel(parent=p_key)
mod.put()
Is this possible and could someone point me in the right direction? Thanks.
回答1:
Following the keys_with_ancestors sample, let's assume we have the same imports and have defined the class MyParent
in the same way it is defined there.
The TL;DR answer is essentially that passing parent=
to the model constructor is equivalent to creating a key with None
as the last ID in the list of kind, ID pairs. For example, for a class MyModel
:
>>> parent = ndb.Key(MyModel, 1)
>>> child = MyModel(parent=parent)
>>> print child.key
ndb.Key('MyModel', 1, 'MyModel', None)
In order to do this with the sample, we could simply ignore the id
:
class MyModel(EndpointsModel):
_parent = None
attr1 = ndb.StringProperty()
attr2 = ndb.StringProperty()
created = ndb.DateTimeProperty(auto_now_add=True)
and in the setter simply set the half-baked key and don't try to retrieve from the datastore (since the key is not complete):
def ParentSet(self, value):
if not isinstance(value, basestring):
raise TypeError('Parent name must be a string.')
self._parent = value
if ndb.Key(MyParent, value).get() is None:
raise endpoints.NotFoundException('Parent %s does not exist.' % value)
self.key = ndb.Key(MyParent, self._parent, MyModel, None)
self._endpoints_query_info.ancestor = ndb.Key(MyParent, value)
Similarly, in the getter, you can just retrieve the parent directly from the key (though this doesn't guarantee there is only a single pair as the parent):
@EndpointsAliasProperty(setter=ParentSet, required=True)
def parent(self):
if self._parent is None and self.key is not None:
self._parent = self.key.parent().string_id()
return self._parent
Having done this you won't need to change any of the API code and the example will work as expected.
来源:https://stackoverflow.com/questions/16051459/setting-parent-key-but-not-child-key-while-using-endpoint-proto-datastore