Cloud Endpoints - 从数据存储区检索单个实体(通过 EndpointsModel 提供的帮助器方法以外的属性)

2023-12-12

这个问题完全源于我在这里提出(并得到回答)的相关问题:尝试检索单个实体时出错

据我了解,要使用已提供的辅助方法以外的属性从数据存储中检索单个实体(例如'id')需要将一个简单的数据属性转换为EndpointsAliasProperty?如果是的话,我该怎么做?还是说我们只能用'id'(由提供的辅助方法EndpointsModel)并且我们不能使用我们定义的任何属性(在本例中'title')?


定制与定制的区别EndpointsAliasPropertys 以及您定义的数据属性之一是它们的使用方式。它们都被用来创建一个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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Cloud Endpoints - 从数据存储区检索单个实体(通过 EndpointsModel 提供的帮助器方法以外的属性) 的相关文章

随机推荐