使用bulkloader上传数据

3 投票
3 回答
604 浏览
提问于 2025-04-16 17:17

简单来说:我该如何配置批量加载器,让它把数据插入到两个有关系的模型中呢?

我有一个“人”和一个“水果”的类,其中“人”类与“水果”类有关联:

class Fruit(db.Model): 
    name = db.StringProperty()
class Person(db.Model): 
    name = db.StringProperty() 
    customer = db.ReferenceProperty(Fruit)

我想上传这个CSV数据:

Name,Fruit
Bob,Banana
Joe,Apple
Tim,Banana

我尝试使用文档中提到的create_foreign_key:

transformers:

- kind: fruit
  connector: csv
  property_map:
    - property: fruit
      external_name: Fruit

- kind: person
  connector: csv
  connector_options:
    encoding: utf-8
    columns: from_header
  property_map:
    - property: title
      external_name: Name
    - property: fruit
      external_name: Fruit
      import_transform: transform.create_foreign_key('fruit')

当我运行这个命令时:

appcfg.py upload_data --config_file=bulkloader.yaml --filename=food.csv --kind=person .

人被上传了,并且他们有指向水果的外键,但他们指向的水果实体并不存在。

当我尝试 --kind=fruit 时,水果被上传了,但出现了很多重复项。

我想把“人”和“水果”关联起来,而且不想有重复的水果,这通过批量加载器可以实现吗?

3 个回答

1

可以通过一个叫做post_import_function的功能来实现。

在你的模型里,不要导入外键。相反,你需要添加一个post_import_function,内容大概是这样的:

def fkeyLocation(input_dict, entity_instance, bulkload_state):
   entity_instance.availableAt =  Location.all().filter('name = ',input_dict['availableAt']).get().key()

   return entity_instance

关键在于使用input_dict来查找。如果你在使用多态模型(polymodels),那么你不能使用向导自动生成的“kind”,而是要用示例代码中的model.modelName,具体可以参考这里

4

当然可以。

这里的基本问题是缺少一个步骤。你有一个水果的名字,但你想存储的是水果的键。你可以通过几种方式来实现这个目标。

如果Banana(香蕉)或Apple(苹果)是水果的永久唯一标识符,你可以使用transform.create_foreign_key('Fruit')。这样你就能得到一个水果键,其中水果名字就是键的名称。这样上传的人会指向那些不存在的水果实体,这没问题。只要在__key__属性上使用相同的导入转换来上传水果,就能创建相应的实体。

如果你不想用水果名字作为水果键的名称,那你就需要做一些更复杂的后期处理。你可以写一个post_import_function,这个函数会根据名字查询水果,看看是否已经存在匹配的实体,如果没有,就创建一个,然后在新创建的人实体上设置对它的引用。

0

我没找到一个简单的方法来做到这一点,所以最后我只是把数据分成了多个文件,并提前生成了ID。

撰写回答