Tik*_*iki 4 google-cloud-endpoints endpoints-proto-datastore
这个问题完全遵循我在这里提出(并得到回答)的相关问题:尝试检索单个实体时出错
据我所知,要使用除已经提供的辅助方法之外的属性从数据存储中检索单个实体(例如'id')需要将简单的数据属性转换为EndpointsAliasProperty?如果是的话,我该怎么做呢?或者我们只能使用'id'(由提供的辅助方法EndpointsModel),我们不能使用我们定义的任何属性(在这种情况下'title')?
bos*_*ter 13
自定义EndpointsAliasPropertys和您定义的某个数据属性之间的区别在于它们的使用方式.它们都用于创建protorpc消息,然后将该消息转换为EndpointsModel包含自定义数据的消息.这就是魔术发生的地方.
将其分解为几个步骤:
from google.appengine.ext import ndb
from endpoints_proto_datastore.ndb import EndpointsModel
class MyModel(EndpointsModel):
my_attr = ndb.StringProperty()
Run Code Online (Sandbox Code Playgroud)
class MyApi(...):
@MyModel.method(request_fields=('id', 'my_attr'), ...)
def my_method(self, my_model_entity):
...
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
每次由装饰的方法处理请求时都会发生这种情况@MyModel.method.
使用protorpc消息类,将从JSON解析消息实例,该消息实例将传递给您的端点SPI(由其创建endpoints.api_server).
当请求进入您protorpc.remote.Service的解码时:
>>> 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'>
Run Code Online (Sandbox Code Playgroud)
protorpc消息被转换为数据存储模型entity = MyModel.FromMessage(request_message)
Run Code Online (Sandbox Code Playgroud)
这是你真正关心的一步.所述FromMessage类方法(还提供了作为其一部分EndpointsModel)遍历所有的字段
for field in sorted(request_message_class.all_fields(),
key=lambda field: field.number):
Run Code Online (Sandbox Code Playgroud)
对于具有值集的每个字段,将值转换为要添加到实体的内容,并根据属性是否为以下内容进行分隔EndpointsAliasProperty:
if isinstance(value_property, EndpointsAliasProperty):
alias_args.append((local_name, to_add))
else:
entity_kwargs[local_name] = to_add
Run Code Online (Sandbox Code Playgroud)
完成此循环后,我们有一个有序列表alias_args,其中包含所有键,值对以及entity_kwargs从消息中解析的数据属性的字典.
使用这些,首先创建一个简单的实体
entity = MyModel(**entity_kwargs)
Run Code Online (Sandbox Code Playgroud)
然后按顺序设置每个别名属性值:
for name, value in alias_args:
setattr(entity, name, value)
Run Code Online (Sandbox Code Playgroud)
扩展行为发生在setattr(entity, name, value).由于EndpointsAliasProperty是的子类property,它是一个描述符,它有一个setter可以执行一些自定义的行为超出了简单的设置值.
例如,该id属性定义为:
@EndpointsAliasProperty(setter=IdSet, property_type=messages.IntegerField)
def id(self):
Run Code Online (Sandbox Code Playgroud)
并setter执行除简单设置数据之外的操作:
def IdSet(self, value):
self.UpdateFromKey(ndb.Key(self.__class__, value))
Run Code Online (Sandbox Code Playgroud)
此特定方法尝试使用id数据存储区中未包含在从请求解析的实体中的任何值中的和补丁来检索存储在数据存储区中的实体.
如果你想为类似的字段执行此操作my_attr,则需要构建一个自定义查询,该查询可以检索具有该唯一my_attr值的项目(如果不存在一个这样的实体则会失败).
这是有问题的,您最好使用唯一字段,例如用于在数据存储区中存储实体的密钥或ID.
具有祖先样本的键提供了创建自己的自定义属性的一个很好的示例.
如果你真的坚持使用my_attr检索实体,你可以使用不同的属性名称(因为my_attr已经用于数据属性),例如fromMyAttr:
class MyModel(EndpointsModel):
def MyAttrSet(self, value):
...
@EndpointsAliasProperty(setter=MyAttrSet)
def fromMyAttr(self):
...
Run Code Online (Sandbox Code Playgroud)
这里,MyAttrSet实例方法将形成查询:
def MyAttrSet(self, value):
query = MyModel.query(MyModel.my_attr == value)
results = query.fetch(2)
Run Code Online (Sandbox Code Playgroud)
拒绝不是唯一的结果my_attr:
if len(results) == 0:
raise endpoints.NotFoundException('Not found.')
if len(results) == 2:
raise endpoints.BadRequestException('Colliding results.')
Run Code Online (Sandbox Code Playgroud)
如果我们找到一个唯一的实体,则复制已存储实体的值:
matching_entity = results[0]
self._CopyFromEntity(matching_entity)
self._from_datastore = True
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1266 次 |
| 最近记录: |