定制与定制的区别EndpointsAliasProperty
s 以及您定义的数据属性之一是它们的使用方式。它们都被用来创建一个protorpc
消息,然后该消息被转换为EndpointsModel
其中包含您的自定义数据。THIS这就是魔法发生的地方。
将其分解为步骤:
1. 您指定您的数据
from google.appengine.ext import ndb
from endpoints_proto_datastore.ndb import EndpointsModel
class MyModel(EndpointsModel):
my_attr = ndb.StringProperty()
2.您为您的方法选择字段
class MyApi(...):
@MyModel.method(request_fields=('id', 'my_attr'), ...)
def my_method(self, my_model_entity):
...
3. A protorpc
消息类别是根据您的字段定义的
>>> request_message_class = MyModel.ProtoModel(fields=('id', 'my_attr'))
>>> request_message_class
<class '.MyModelProto_id_my_attr'>
>>> for field in request_message_class.all_fields():
... print field.name, ':', field.variant
...
id : INT64
my_attr : STRING
有时候是这样的每次请求由装饰有的方法处理@MyModel.method
.
4. 您的应用程序收到请求并创建一条消息
使用protorpc
消息类,从传递到端点的 JSON 中解析消息实例SPI(它是由endpoints.api_server
).
当请求到达您的protorpc.remote.Service
it is decoded:
>>> from protorpc import remote
>>> protocols = remote.Protocols.get_default()
>>> json_protocol = protocols.lookup_by_content_type('application/json')
>>> request_message = json_protocol.decode_message(
... request_message_class,
... '{"id": 123, "my_attr": "some-string"}'
... )
>>> request_message
<MyModelProto_id_my_attr
id: 123
my_attr: u'some-string'>
5. The protorpc
消息是转换为数据存储模型
entity = MyModel.FromMessage(request_message)
THIS是您真正关心的步骤。这FromMessage
类方法(也作为EndpointsModel
) 循环遍历所有字段
for field in sorted(request_message_class.all_fields(),
key=lambda field: field.number):
对于设置了值的每个字段,将值转换为要添加到实体中的内容,并根据属性是否为属性进行分离EndpointsAliasProperty
or not:
if isinstance(value_property, EndpointsAliasProperty):
alias_args.append((local_name, to_add))
else:
entity_kwargs[local_name] = to_add
完成这个循环后,我们有一个有序列表alias_args
所有键、值对和字典entity_kwargs
从消息中解析的数据属性。
使用这些,首先是一个简单的实体被建造
entity = MyModel(**entity_kwargs)
然后设置每个别名属性值in order:
for name, value in alias_args:
setattr(entity, name, value)
扩展行为发生在setattr(entity, name, value)
. Since EndpointsAliasProperty
是一个子类property,它是一个描述符,它有一个setter
它可以执行一些自定义行为beyond只需设置一个值。
例如,id
财产是定义为:
@EndpointsAliasProperty(setter=IdSet, property_type=messages.IntegerField)
def id(self):
and the setter执行的操作不仅仅是简单地设置数据:
def IdSet(self, value):
self.UpdateFromKey(ndb.Key(self.__class__, value))
此特定方法尝试使用以下方法检索存储在数据存储中的实体id
并修补数据存储中未包含在从请求解析的实体中的任何值。
如果您想对这样的领域执行此操作my_attr
,您需要构建一个自定义查询,该查询可以检索具有该唯一的项目my_attr
值(如果不存在这样一个实体,则失败)。
这是有问题的,您最好使用唯一字段,例如用于在数据存储中存储实体的键或 ID。
The 与祖先的钥匙示例提供了创建您自己的自定义属性的一个很好的示例。
If you REALLY坚持使用my_attr
要检索实体,您可以使用不同的属性名称来执行此操作(因为my_attr
已用于数据属性),例如fromMyAttr
:
class MyModel(EndpointsModel):
def MyAttrSet(self, value):
...
@EndpointsAliasProperty(setter=MyAttrSet)
def fromMyAttr(self):
...
在这里,MyAttrSet
实例方法将形成查询:
def MyAttrSet(self, value):
query = MyModel.query(MyModel.my_attr == value)
results = query.fetch(2)
拒绝不唯一的结果my_attr
:
if len(results) == 0:
raise endpoints.NotFoundException('Not found.')
if len(results) == 2:
raise endpoints.BadRequestException('Colliding results.')
如果我们确实找到了唯一的实体,则复制已存储实体的值:
matching_entity = results[0]
self._CopyFromEntity(matching_entity)
self._from_datastore = True