如何将GAE中的所有实体复制到另一种类型而不明确地调用每个属性

时间:2013-01-14 06:51:57

标签: python google-app-engine google-cloud-datastore

我们如何使用Copy an entity in Google App Engine datastore in Python without knowing property names at 'compile' time中描述的function clone_entity()将值复制到另一种实体中? (因为密钥也被复制,所以克隆发生在同一种类中,所以上述链接的解决方案不能用于此特定目的!)

尝试以下(以及其他变化但无效)

query = db.GqlQuery("SELECT * FROM OrigKind")
results = query.fetch(10);

for user in results:
    new_entry = models.NewKind()
    new_entry_complete_key = new_entry.put()
    new_entry = clone_entity(user, Key=new_entry_complete_key)
    new_entry.put()

(需要将所有实体从 OrigKind 复制到 NewKind

3 个答案:

答案 0 :(得分:4)

您需要clone_entity的修改版本:

在原始实现的答案中讨论的original clone method存在一些缺陷。

def clone_entity(e, to_klass, **extra_args):
  """Clones an entity, adding or overriding constructor attributes.

  The cloned entity will have exactly the same property values as the original
  entity, except where overridden. By default it will have no parent entity or
  key name, unless supplied.

  Args:
    e: The entity to clone
    extra_args: Keyword arguments to override from the cloned entity and pass
      to the constructor.
  Returns:
    A cloned, possibly modified, copy of entity e.
  """
  klass = e.__class__
  props = dict((k, v.__get__(e, klass)) for k, v in klass.properties().iteritems())
  props.update(extra_args)
  return to_klass(**props)

# Use the clone method
query = db.GqlQuery("SELECT * FROM OrigKind")
results = query.fetch(10);

for user in results:
    new_entry = clone_entity(user, NewKind)
    new_entry.put()

答案 1 :(得分:2)

我想在Shay的回答中添加一些内容:

  • 处理to_klass没有e属性的情况。
  • 调整clone_entity方法以使用ndb.Model

def clone_entity(e, to_klass, **extra_args):
    """Clones an entity, adding or overriding constructor attributes.

    The cloned entity will have exactly the same property values as the original
    entity, except where overridden or missing in to_klass. By default it will have 
    no parent entity or key name, unless supplied.

    Args:
      e: The entity to clone
      to_klass: The target class
      extra_args: Keyword arguments to override from the cloned entity and pass
        to the constructor.
    Returns:
      A cloned, possibly modified, instance of to_klass with the same properties as e.
    """
    klass = e.__class__
    props = dict((k, v.__get__(e, klass))
                 for k, v in klass._properties.iteritems()
                 if type(v) is not ndb.ComputedProperty
    )
    props.update(extra_args)
    allowed_props = to_klass._properties
    for key in props.keys():
        if key not in allowed_props:
            del props[key]
    return to_klass(**props)

答案 2 :(得分:1)

它只是编写了一个实用程序,用于将enties从一个appid复制到另一个appid并压缩一种实体。此实用程序生成一个精确的克隆,包括键,NDB重复属性,serve_urls和类型中引用的blob。为了完成这项工作,我必须知道实体的属性类型。我使用Python 27和NDB,但该实用程序还传输db.Models。

以下是查找某种类型的所有属性类型的代码:

    self.kind = 'Books'                                                    # the entities to copy
    self.model_mods = {'Books' : 'models'}                                 # modules to import the model from for a kind

    module = __import__(self.model_mods[self.kind], globals(), locals(), [self.kind], -1)
    self.model_class = getattr(module, self.kind)

    entity = self.model_class()                                            # ndb or db
    if isinstance(entity, ndb.Model): 
        self.ndb = True
        self.query = self.model_class.query()                              # prepare the query to get all the entities 
        self.makePage = self._pager(self.ndbPager)                         # wrap the ndb pager
    elif isinstance(entity, db.Model): 
        self.ndb = False
        self.query = self.model_class.all()
        self.makePage = self._pager(self.dbPager)                          # wrap the db pager
    else :
        raise ValueError('Failed to classify entities of kind : ' + str(self.kind))
    logging.info('Entities of kind : %s inherits from class : %s.Model' 
                 %(self.kind, self.ndb * 'ndb' + (not self.ndb) * 'db'))

    self.data_types = {}                                                   # create a dict of property data types                                         
    for key in self.model_class._properties :                              # the internals of the model_class object
        property_object = getattr(self.model_class, key.split('.')[0])     # strip, so it works for repeated structured properties
        self.data_types[key] = property_object.__class__.__name__          # get the property type
    logging.debug(self.data_types)

在上面的代码中,我为db或NDB包装了一个寻呼机(使用游标进行分页传输),以便在GAE appid之间传输实体。

根据属性,我可以对属性进行编码和解码以传输模型。为此,我首先使用NDB : entity.to_dict() or db: entity.to_dict()创建实体的dict。我把关键词添加到词典中。现在,我可以对实体的属性进行编码,并对结果进行pickle以传输编码实体:

data = pickle.dumps(entity_dict, 1)
encoded_entity = base64.b64encode(data)