3

db.SelfReferencePropertyツリーのような構造を作成するために使用しているクラスがあります。

を使用してデータベースにデータを入力しようとするとappcfg.py upload_data -- config_file=bulkloader.yaml --kind=Group --filename=group.csv (...) 、例外が発生しますBadValueError: name must not be empty(以下のフルスタック)

データを並べ替えて、それらを指している外部キーを持つグループが最初になるようにしました。それはうまくいきませんでした。

変換を行う行 "import_transform: transform.create_foreign_key('Group')" を bulkloader.yaml からコメントすると、データはアップロードされますが、そのプロパティが文字列として保存され、アプリケーション ロジックが壊れます。

- kind: Group
  connector: csv
  connector_options:
  property_map:
    - property: __key__
      external_name: key
      export_transform: transform.key_id_or_name_as_string

    - property: name
      external_name: name
      # Type: String Stats: 9 properties of this type in this kind.

    - property: section
      external_name: section
      # Type: Key Stats: 6 properties of this type in this kind.
      import_transform: transform.create_foreign_key('Group')
      export_transform: transform.key_id_or_name_as_string

バルクローダーに自己参照を考慮させる方法はありますか、またはバルクロードされたデータの変換サーバーサイドを作成するか、独自のバルクロードアルゴリズムを実装する必要がありますか?

----
Traceback (most recent call last):
  File "/home/username/src/google_appengine/google/appengine/tools/adaptive_thread_pool.py", line 150, in WorkOnItems
    status, instruction = item.PerformWork(self.__thread_pool)
  File "/home/username/src/google_appengine/google/appengine/tools/bulkloader.py", line 691, in PerformWork
    transfer_time = self._TransferItem(thread_pool)
  File "/home/username/src/google_appengine/google/appengine/tools/bulkloader.py", line 846, in _TransferItem
    self.content = self.request_manager.EncodeContent(self.rows)
  File "/home/username/src/google_appengine/google/appengine/tools/bulkloader.py", line 1267, in EncodeContent
    entity = loader.create_entity(values, key_name=key, parent=parent)
  File "/home/username/src/google_appengine/google/appengine/ext/bulkload/bulkloader_config.py", line 382, in create_entity
    return self.dict_to_entity(input_dict, self.bulkload_state)
  File "/home/username/src/google_appengine/google/appengine/ext/bulkload/bulkloader_config.py", line 133, in dict_to_entity
    self.__run_import_transforms(input_dict, instance, bulkload_state_copy)
  File "/home/username/src/google_appengine/google/appengine/ext/bulkload/bulkloader_config.py", line 230, in __run_import_transforms
    value = self.__dict_to_prop(transform, input_dict, bulkload_state)
  File "/home/username/src/google_appengine/google/appengine/ext/bulkload/bulkloader_config.py", line 188, in __dict_to_prop
    value = transform.import_transform(value)
  File "/home/username/src/google_appengine/google/appengine/ext/bulkload/bulkloader_parser.py", line 93, in __call__
    return self.method(*args, **kwargs)
  File "/home/username/src/google_appengine/google/appengine/ext/bulkload/transform.py", line 114, in generate_foreign_key_lambda
        return datastore.Key.from_path(kind, value)
  File "/home/username/src/google_appengine/google/appengine/api/datastore_types.py", line 384, in from_path
    ValidateString(id_or_name, 'name')
  File "/home/username/src/google_appengine/google/appengine/api/datastore_types.py", line 109, in ValidateString
    raise exception('%s must not be empty.' % name)
BadValueError: name must not be empty.

4

2 に答える 2

4

同様の問題に対する回答をベースとして使用helpers.pyして、ラッパーとして機能する小さなファイルを作成することで、これをうまく解決できましたtransform.create_foreign_key

from google.appengine.api import datastore

def create_foreign_key(kind, key_is_id=False):
  def generate_foreign_key_lambda(value):
    if value is None:
      return None

    if key_is_id:
      value = int(value)
    try:
      return datastore.Key.from_path(kind, value)
    except:
      return None

  return generate_foreign_key_lambda

そのファイルを yaml 一括アップロード構成ファイル ( bulkloader.yaml) と同じディレクトリに配置したら、これをそのファイルに追加します。

python_preamble:
- (...)
- import: helpers

transformers:

- kind: Group
  connector: csv
  connector_options:
  property_map:
    - property: __key__
      external_name: key
      export_transform: transform.key_id_or_name_as_string

    - property: name
      external_name: name

    - property: section
      external_name: section
      import_transform: helpers.create_foreign_key('Group')
                      # ^^^^^^^ we use the wrapper instead
      export_transform: transform.key_id_or_name_as_string

これらの変更により、一括アップロードが正しく機能するようになりました。

これを使用する前に、必ず catch allexceptを変更し、 may be に置き換えてexcept BadValueErrorください。

于 2010-09-13T22:44:43.290 に答える
2

transform.py(たぶん最近) この問題を解決するデコレータが含まれています:

def none_if_empty(fn):
  """A decorator which returns None if its input is empty else fn(x).

  Useful on import.  Can be used in config files
  (e.g. "transform.none_if_empty(int)" or as a decorator.

  Args:
    fn: Single argument transform function.

  Returns:
    Wrapped function.
  """

  def wrapper(value):


    if value == '' or value is None or value == []:
      return None
    return fn(value)

  return wrapper

そのため、カスタムhelpers.pyファイルを導入しなくても、以下を使用しても問題は解決します。

transform.none_if_empty(transform.create_foreign_key('Group'))
于 2011-08-31T12:29:23.163 に答える