GCP Proto Datastore 在 base64 中编码 JsonProperty

GCP Proto Datastore encode JsonProperty in base64

我使用 JsonProperty 在数据存储中存储了一个 Json 的 blob。 我不知道 json 数据的结构。

我正在使用 endpoints proto datastore 来检索我的数据。

问题是 json 属性 是用 base64 编码的,我想要一个普通的 json 对象。

例如,json 数据将为:

{
    first: 1,
    second: 2
}

我的代码类似于:

import endpoints
from google.appengine.ext import ndb
from protorpc import remote
from endpoints_proto_datastore.ndb import EndpointsModel


class Model(EndpointsModel):
    data = ndb.JsonProperty()


@endpoints.api(name='myapi', version='v1', description='My Sample API')
class DataEndpoint(remote.Service):

    @Model.method(path='mymodel2', http_method='POST',
                  name='mymodel.insert')
    def MyModelInsert(self, my_model):
        my_model.data = {"first": 1, "second": 2}
        my_model.put()
        return my_model

    @Model.method(path='mymodel/{entityKey}',
                  http_method='GET',
                  name='mymodel.get')
    def getMyModel(self, model):
        print(model.data)
        return model


API = endpoints.api_server([DataEndpoint])

当我调用 api 获取模型时,我得到:

POST /_ah/api/myapi/v1/mymodel2
{
    "data": "eyJzZWNvbmQiOiAyLCAiZmlyc3QiOiAxfQ=="
}

其中 eyJzZWNvbmQiOiAyLCAiZmlyc3QiOiAxfQ=={"second": 2, "first": 1}

的 base64 编码

打印语句给我:{u'second': 2, u'first': 1}

因此,在该方法中,我可以将 json blob 数据作为 python dict 进行探索。 但是,在 api 调用中,数据以 base64 编码。

我加急了 api 电话给我:

{
    'data': {
        'second': 2,
        'first': 1
     }
}

我怎样才能得到这个结果?

在您的问题的评论中进行讨论后,让我与您分享一个示例代码,您可以使用它在 Datastore 中存储一个 JSON 对象(它将存储为一个字符串),然后以这样的方式检索它:

  • 在 API 调用后将显示为普通 JSON。
  • 您将能够使用 eval.
  • 再次将其解析为 Python 字典

希望我正确理解了您的问题,这对您有所帮助。

import endpoints
from google.appengine.ext import ndb
from protorpc import remote
from endpoints_proto_datastore.ndb import EndpointsModel

class Sample(EndpointsModel):
  column1 = ndb.StringProperty()
  column2 = ndb.IntegerProperty()
  column3 = ndb.StringProperty()

@endpoints.api(name='myapi', version='v1', description='My Sample API')
class MyApi(remote.Service):
  # URL: .../_ah/api/myapi/v1/mymodel - POSTS A NEW ENTITY
  @Sample.method(path='mymodel', http_method='GET', name='Sample.insert')
  def MyModelInsert(self, my_model):
    dict={'first':1, 'second':2}
    dict_str=str(dict)

    my_model.column1="Year"
    my_model.column2=2018
    my_model.column3=dict_str
    my_model.put()
    return my_model

  # URL: .../_ah/api/myapi/v1/mymodel/{ID} - RETRIEVES AN ENTITY BY ITS ID
  @Sample.method(request_fields=('id',), path='mymodel/{id}', http_method='GET', name='Sample.get')
  def MyModelGet(self, my_model):
    if not my_model.from_datastore:
      raise endpoints.NotFoundException('MyModel not found.')

    dict=eval(my_model.column3)
    print("This is the Python dict recovered from a string: {}".format(dict))

    return my_model

application = endpoints.api_server([MyApi], restricted=False)

我已经使用开发服务器测试了这段代码,但在生产环境中使用带有端点和数据存储的 App Engine 应该也能正常工作。

查询第一个端点后,它将创建一个新实体,您可以在 Datastore 中找到该实体,其中包含 属性 column3 以及您的 JSON 数据字符串格式:

然后,如果您使用该实体的 ID 检索它,在您的浏览器中它将显示没有任何奇怪编码的字符串,只是普通的 JSON:

并且在控制台中,您将能够看到该字符串可以转换为 Python 字典(或者也可以是 JSON,如果您使用 json 模块更喜欢):

我希望我没有漏掉你想要实现的任何一点,但我认为所有最重要的点都包含在这段代码中:属性 是一个 JSON 对象,存储它在数据存储中,以可读格式检索它,并能够再次使用它作为 JSON/dict.


更新:

我认为您应该自己看看 list of available Property Types,以便找到更符合您要求的那个。但是,作为附加说明,我通过对代码添加以下修改,对 StructuredProperty(另一个 属性 中的 属性)进行了快速测试:

#Define the nested model (your JSON object)
class Structured(EndpointsModel):
  first = ndb.IntegerProperty()
  second = ndb.IntegerProperty()

#Here I added a new property for simplicity; remember, Whosebug does not write code for you :)
class Sample(EndpointsModel):
  column1 = ndb.StringProperty()
  column2 = ndb.IntegerProperty()
  column3 = ndb.StringProperty()
  column4 = ndb.StructuredProperty(Structured)

#Modify this endpoint definition to add a new property
@Sample.method(request_fields=('id',), path='mymodel/{id}', http_method='GET', name='Sample.get')
  def MyModelGet(self, my_model):
    if not my_model.from_datastore:
      raise endpoints.NotFoundException('MyModel not found.')

    #Add the new nested property here
    dict=eval(my_model.column3)
    my_model.column4=dict
    print(json.dumps(my_model.column3))
    print("This is the Python dict recovered from a string: {}".format(dict))

    return my_model

进行这些更改后,对端点的调用响应如下所示:

现在 column4 是一个 JSON 对象本身(虽然它没有被打印出来 in-line,我认为这应该不是问题。

我希望这也能有所帮助。如果这不是您想要的确切行为,也许应该使用可用的 属性 类型,但我认为没有一种类型可以打印 Python 字典(或 JSON object) 而不是事先将其转换为 String.