Google app engine GAE:下载数据时出错,如果ndb.KeyProperty(repeated=True)

Google app engine GAE:下载数据时出错,如果ndb.KeyProperty(repeated=True),google-app-engine,app-engine-ndb,Google App Engine,App Engine Ndb,我正在从现有架构自动创建bulkloader.yaml,由于KeyProperty的repeated=True,下载数据时遇到问题 class User(ndb.Model): firstname = ndb.StringProperty() friends = ndb.KeyProperty(kind='User', repeated=True) 自动创建的bulkloader如下所示: - kind: User connector: csv connector_o

我正在从现有架构自动创建bulkloader.yaml,由于KeyProperty的
repeated=True
,下载数据时遇到问题

class User(ndb.Model):
    firstname = ndb.StringProperty()
    friends = ndb.KeyProperty(kind='User', repeated=True) 
自动创建的bulkloader如下所示:

- kind: User
  connector: csv
  connector_options:
    # TODO: Add connector options here--these are specific to each connector.
  property_map:
    - property: __key__
      external_name: key
      export_transform: transform.key_id_or_name_as_string

    - property: firstname
      external_name: firstname
      # Type: String Stats: 2 properties of this type in this kind.

    - property: friends
      external_name: friends
      # Type: Key Stats: 2 properties of this type in this kind.
      import_transform: transform.create_foreign_key('User')
      export_transform: transform.key_id_or_name_as_string
[datastore_types.Key.from_path(u'User', u'kave@gmail.com', _app=u's~myapp1')] 
这是我收到的错误消息:

google.appengine.ext.bulkload.bulkloader_errors.ErrorOnTransform: Error on transform. Property: friends External Name: friends. Code: transform.key_id_or_name_as_string Details: 'list' object has no attribute 'to_path'
请问我能做什么

可能的解决方案:

在Tony给我小费后,我想到了这个:

- property: friends
      external_name: friends
      # Type: Key Stats: 2 properties of this type in this kind.
      import_transform: myfriends.stringToValue(';') 
      export_transform: myfriends.valueToString(';')
myfriends.py

def valueToString(delimiter):
    def key_list_to_string(value):
        keyStringList = []
        if value == '' or value is None or value == []:
            return None 
        for val in value:                
            keyStringList.append(transform.key_id_or_name_as_string(val))        
        return delimiter.join(keyStringList)
    return key_list_to_string
这很有效!但是编码是Unicode的:UTF-8。确保在LibreOffice中打开文件,否则会看到乱码内容

最大的挑战是进口。这就是我在没有任何运气的情况下想到的:

def stringToValue(delimiter):    
    def string_to_key_list(value):
        keyvalueList = []
        if value == '' or value is None or value == []:
            return None        
        for val in value.split(';'):            
            keyvalueList.append(transform.create_foreign_key('User'))        
        return keyvalueList
    return string_to_key_list
我收到错误消息:

BadValueError: Unsupported type for property friends: <type 'function'>
更新2:

托尼,你将成为散货船方面的真正专家。谢谢你的帮助。你的解决方案奏效了! 我把我的另一个问题转移到一个新的话题上

但出现的一个关键问题是,当我创建新用户时,我可以看到我的
朋友
字段显示为
,并且工作正常

现在,当我使用您的解决方案上载数据时,对于那些没有任何好友条目的用户,我看到了一个
条目。不幸的是,这似乎打破了模型,因为friends不能为null

改变模型以反映这一点似乎被忽略了

friends = ndb.KeyProperty(kind='User', repeated=True, required=False)
请问我该怎么修

更新:

进一步挖掘: 当状态
显示在data viewer中时,在代码中会显示
friends=[]
然而,当我通过csv上传数据时,我得到了一个
,它转换为
朋友=[None]
。我知道这一点,因为我将数据导出到本地数据存储中,并可以在代码中跟踪它。奇怪的是,如果我清空列表
del user.friends[:]
,它会正常工作。必须有一个更好的方式来设置它,而上传通过csv虽然

最终解决方案

这是一个一年多以来一直没有解决的问题

简而言之,即使csv中没有值,因为需要一个列表,gae也会生成一个包含None的列表。这是一个突破性的游戏,因为这样一个模型的检索以瞬间崩溃告终

添加一个
post\u import\u函数
,该函数将删除包含None的列表

就我而言:

def post_import(input_dict, instance, bulkload_state_copy):
    if instance["friends"] is None:
        del instance["friends"]
    return instance

最后,一切正常。

当您使用重复属性并导出到CSV时,您应该进行一些格式化,以将列表连接到CSV可理解的格式。请检查下面的示例,希望它能帮助您

编辑:添加从先前注释到此答案的导入转换建议


要导入,请尝试以下操作:

 `from google.appengine.api import datastore 
    def stringToValue(delimiter): 
        def string_to_key_list(value): 
            keyvalueList = [] 
            if value == '' or value is None or value == []: return None 
            for val in value.split(';'): 
                keyvalueList.append(datastore.Key.from_path('User', val)) 
            return keyvalueList 
        return string_to_key_list`

如果您使用的是id而不是名称,请添加类似val=int(val)

当您使用重复属性并导出到CSV时,您应该进行一些格式化,以将列表连接到CSV可理解的格式。请检查下面的示例,希望它能帮助您

编辑:添加从先前注释到此答案的导入转换建议


要导入,请尝试以下操作:

 `from google.appengine.api import datastore 
    def stringToValue(delimiter): 
        def string_to_key_list(value): 
            keyvalueList = [] 
            if value == '' or value is None or value == []: return None 
            for val in value.split(';'): 
                keyvalueList.append(datastore.Key.from_path('User', val)) 
            return keyvalueList 
        return string_to_key_list`

如果您有id而不是姓名,请添加类似val=int(val)

Tony,非常感谢您的帮助。我已经成功地完成了导出,并且成功了。但就我而言,进口是非常困难的。你知道我怎么做吗?请参阅更新的问题。对于导入,请尝试以下操作:
from google.appengine.api导入数据存储def stringToValue(分隔符):def string_to_key_list(value):keyvalueList=[]如果value=''或value为None或value=[]:为value中的val返回None。拆分(“;”):keyvalueList.append(datastore.Key.from_path('User',val))return keyvalueList return string_to_Key_list
如果您有id而不是名称,请添加like val=int(val)Tony,如果您将导入建议放在主要答案中,则可以正确格式化它。:-)@GuidovanRossum,我已经将代码建议移到我的答案中,以获得正确的格式。请您看看代码逻辑是否正确。@tony,非常感谢您在这方面的帮助。是的,它似乎起了作用。但有一个相关的问题,我已经在更新的问题中解释过。GAE分配了非常高的id,这在重新上传时成为一个问题。托尼,非常感谢你的帮助。我已经成功地完成了导出,并且成功了。但就我而言,进口是非常困难的。你知道我怎么做吗?请参阅更新的问题。对于导入,请尝试以下操作:
from google.appengine.api导入数据存储def stringToValue(分隔符):def string_to_key_list(value):keyvalueList=[]如果value=''或value为None或value=[]:为value中的val返回None。拆分(“;”):keyvalueList.append(datastore.Key.from_path('User',val))return keyvalueList return string_to_Key_list
如果您有id而不是名称,请添加like val=int(val)Tony,如果您将导入建议放在主要答案中,则可以正确格式化它。:-)@GuidovanRossum,我已经将代码建议移到我的答案中,以获得正确的格式。请您看看代码逻辑是否正确。@tony,非常感谢您在这方面的帮助。是的,它似乎起了作用。但有一个相关的问题,我已经在更新的问题中解释过。GAE分配非常高的id,这在重新上传时成为一个问题。