Cómo COPIAR todas las entidades de una Clase en GAE a otra Clase sin llamar explícitamente a cada propiedad

¿Cómo utilizamos la function clone_entity() como se describe en Copiar una entidad en el almacén de datos de Google App Engine en Python sin saber los nombres de las propiedades en el momento de ‘comstackción’ para copiar los valores a una entidad de un tipo diferente? (dado que las claves también se copian, la clonación se realiza de la misma forma, por lo que la solución en el enlace anterior no funciona para este propósito en particular)

Intenté lo siguiente (y otras variaciones pero sin resultado)

 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() 

(Necesito copiar todas las entidades de OrigKind a NewKind )

Necesitas una versión modificada de clone_entity :

Hay algunas trampas en el método de clonación original que se analizan en las respuestas de la implementación original.

 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() 

Me gustaría agregar un par de cosas a la respuesta de Shay:

  • Tratando el caso donde to_klass no tiene propiedades que e.
  • Adaptar el método clone_entity para trabajar con 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) 

Acaba de escribir una utilidad para copiar entidades de un appid a otro y para comprimir entidades de un tipo. Esta utilidad hace un clon exacto, incluyendo claves, propiedades repetidas de NDB, serve_urls y blobs referenciados en el tipo. Para hacer este trabajo tengo que conocer los tipos de propiedad de las entidades. Utilizo Python 27 y NDB, pero la utilidad también transfiere db.Models.

Aquí está el código para encontrar todos los tipos de propiedad para un tipo:

  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) 

En el código anterior, envuelvo un paginador (transferencia paginada con un cursor) para db o NDB para transferir las entidades entre las aplicaciones de GAE.

Según las propiedades, puedo codificar y decodificar las propiedades para transferir el modelo. Para hacer esto, primero creo un dictado de las entidades que usan NDB : entity.to_dict() or db: entity.to_dict() . Y añado la clave al dict. Ahora puedo codificar las propiedades de la entidad y decapar el resultado para transferir la entidad codificada:

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