既存のスキーマから自動的に bulkloader.yaml を作成していますrepeated=True
が、KeyProperty が原因でデータのダウンロードに問題があります。
class User(ndb.Model):
firstname = ndb.StringProperty()
friends = ndb.KeyProperty(kind='User', repeated=True)
自動作成されたバルクローダーは次のようになります。
- 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'
どうすればいいですか?
考えられる解決策:
トニーのヒントの後、私はこれを思いつきました:
- 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 ビューアーによると、次のようなものを作成する必要があります。
[datastore_types.Key.from_path(u'User', u'kave@gmail.com', _app=u's~myapp1')]
更新 2:
トニー、あなたは Bulkloader の真の専門家です。ご協力いただきありがとうございます。あなたのソリューションはうまくいきました!別の質問を新しいスレッドに移動しました。
しかし、表示される重大な問題の 1 つは、新しいユーザーを作成すると、自分のfriends
フィールドが次のように表示され<missing>
、正常に機能することです。
ソリューションを使用してデータをアップロードすると、友人のエントリがないユーザーのエントリが表示されます<null>
。残念ながら、友人を null にすることはできないため、これはモデルを壊しているようです。
これを反映するようにモデルを変更すると、無視されるようです。
friends = ndb.KeyProperty(kind='User', repeated=True, required=False)
どうすればこれを修正できますか?
アップデート:
さらに掘り下げます:<missing>
データ ビューアーにステータスが表示されると、コードで表示されますが、friends = []
csv 経由でデータをアップロードすると<null>
、 に変換されfriends = [None]
ます。データをローカル データ ストレージにエクスポートし、それをコードで追跡できたので、私はこれを知っています。奇妙なことに、リストを空にすると、del user.friends[:]
期待どおりに機能します。ただし、csv経由でアップロードするときに設定するより良い方法があるはずです...
最終的解決
これは、1 年以上解決されていないバグであることが判明しました。
要するに、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
最後に、すべてが期待どおりに機能します。