我正在从现有架构中自动创建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
最后一切都按预期工作。
答案 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)