This post向我展示了如何设置父子模型关系。一切正常,但我无法作为特定实体获取,就像在simple_get示例中一样。
我试图用路径=' mymodel / {parent} / {id}'来装饰.method。但是model.from_datastore总是假的。
非常感谢任何关于如何正确接线的建议。
感谢。
答案 0 :(得分:0)
好的,这是鸡和蛋的问题。 Here is the solution。我创建了一个基类:
class BaseChildModel(EndpointsModel):
"""
Base child model class.
"""
# this needs to be set by inheritor
# this is a class of the NDB Entity parent,
# not an inheritance
parent_model_class = None
# These values are placeholders to be used when a key is created; the _parent
# will be used as the ancestor and the _id as the ID. For example:
# ndb.Key(parent_class, _parent, self.__class__, _id)
# Since these values will be set by alias properties which are not set
# simultaneously, we need to hold them around until both are present before we
# can create a key from them.
_parent = None
_id = None
# This is a helper method that will set the key on the entity only if both the
# parent and ID are present. It will be used by property setters that provide
# values for _parent and _id.
def set_key(self):
# if _parent ID is present, let's set the key
if self._parent is not None:
# we don't care if _id is None, the key like this will generate child ID
# for newly inserted child while keeping parent ID; i.e. this is insert
self._key = key = ndb.Key(self.__class__.parent_model_class, self._parent, self.__class__, self._id)
if self._id is not None:
# this is update/retrieve of existing child
# Will set the key and attempt to update the entity if it exists.
self.UpdateFromKey(key)
# This is a helper method that will set the _parent and _id values using the
# entity key, if it exists. It will be used by property getters that retrieve
# the current values of _parent and _id.
def set_parts(self):
# If there is no key, nothing can be set.
if self.key is not None:
# If there are not two tuples in the key pairs, a ValueError will occur.
parent_pair, id_pair = self.key.pairs()
# Each pair in key pairs will be a tuple (model kind, value) where model
# kind is a string representing the name of the model and value is the
# actual string or integer ID that was set.
self._parent = parent_pair[1]
self._id = id_pair[1]
# This is a setter which will be used by the alias property "parent". This
# method will be called when parent is set from a ProtoRPC request.
def parent_set(self, value):
self._parent = value
# After setting the value, we must make sure the parent exists before it can
# be used as an ancestor.
if ndb.Key(self.__class__.parent_model_class, value).get() is None:
# If the Parent key does not correspond to an entity in the datastore,
# we return an HTTP 404 Not Found.
raise endpoints.NotFoundException('Parent with id %s does not exist.' % value)
# The helper method SetKey is called to set the entity key if the _id has
# also been set already.
self.set_key()
# If the "parent" property is used in a query method, we want the ancestor
# of the query to be the parent key.
self._endpoints_query_info.ancestor = ndb.Key(self.__class__.parent_model_class, value)
# This EndpointsAliasProperty is used to get and set a parent for our entity
# key. It is required, meaning that a value must always be set if the
# corresponding field is contained in a ProtoRPC message schema.
@EndpointsAliasProperty(setter=parent_set, required=True, property_type=messages.IntegerField)
def parent(self):
# If _parent has not already been set on the entity, try to set it.
if self._parent is None:
# Using the helper method SetParts, _parent will be set if a valid key has
# been set on the entity.
self.set_parts()
return self._parent
# This is a setter which will be used by the alias property "id". This
# method will be called when id is set from a ProtoRPC request. This replaces
# the helper property "id" provided by EndpointsModel, but does not use any of
# the functionality from that method.
def IdSet(self, value):
self._id = value
# The helper method SetKey is called to set the entity key if the _parent
# has also been set already.
self.set_key()
# This EndpointsAliasProperty is used to get and set an id value for our
# entity key. It is required, meaning that a value must always be set if the
# corresponding field is contained in a ProtoRPC message schema.
@EndpointsAliasProperty(setter=IdSet, required=True, property_type=messages.IntegerField)
def id(self):
# If _id has not already been set on the entity, try to set it.
if self._id is None:
# Using the helper method SetParts, _id will be set if a valid key has
# been set on the entity.
self.set_parts()
return self._id
使用this example,应该像这样使用:
class MyModel(BaseChildModel):
parent_model_class = MyParent
attr1 = ndb.StringProperty()
attr2 = ndb.StringProperty()
created = ndb.DateTimeProperty(auto_now_add=True)
这样就行了:
@MyModel.method(user_required=True,
http_method='PUT',
path='my_model/{parent}/{id}',
name='my_model.update')
def MyModelUpdate(self, my_model):
if not my_model.from_datastore:
raise endpoints.NotFoundException('my_model not found.')
my_model.modified_by = endpoints.get_current_user()
my_model.put()
return my_model