GAE:下载数据时出错,如果是ndb.KeyProperty(重复= True)

时间:2013-07-05 09:14:07

标签: 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_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

这是我收到的错误消息:

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'>

根据数据存储区查看器,我需要创建这样的东西:

[datastore_types.Key.from_path(u'User', u'kave@gmail.com', _app=u's~myapp1')] 

更新2:

托尼,你将成为Bulkloader的真正专家。谢谢你的帮助。您的解决方案有效 我已经将我的另一个问题转移到一个新的主题。

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

现在,当我使用您的解决方案上传数据时,我会看到没有任何朋友条目的用户<null>条目。不幸的是,这似乎打破了模型,因为朋友不能为空。

更改模型以反映这一点,似乎被忽略了。

friends = ndb.KeyProperty(kind='User', repeated=True, required=False)

我该如何解决这个问题?

更新

进一步深入研究: 当状态<missing>显示在数据查看器中时,在代码中显示friends = [] 但是,当我通过csv上传数据时,我会得到一个<null>,转换为friends = [None]。我知道这一点,因为我将数据导出到我的本地数据存储中,并且可以在代码中跟踪它。奇怪的是,如果我清空列表del user.friends[:],它会按预期工作。通过csv上传时必须有一种更好的方式来设置它...

最终解决方案

事实证明这是一个bug,自一年多以来一直没有得到解决。

简而言之,即使csv中没有值,因为预期列表,gae会生成一个内部为None的列表。这是游戏破坏,因为这种模型的检索最终会立即崩溃。

添加post_import_function,删除内部为None的列表。

就我而言:

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

最后一切都按预期工作。

1 个答案:

答案 0 :(得分:1)

当您使用重复属性并导出为CSV时,您应该进行一些格式化以将列表连接成CSV理解格式。请查看import/export of list of dates上的示例,希望它能为您提供帮助。

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

如需导入,请尝试以下内容:

 `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而不是name,请添加val = int(val)