2

I have a collection of entities with both parent keys and string ids. Sometimes I need to change the string id (update the entity with a new id). From this question (Modify a Google App Engine entity id?), it looks like I need to create a new entity and delete the old one.

Of course, I want to preserve all of the properties in the old entity when creating the new one, but there doesn't seem to be a clone method for NDB entities.

Is this the best way to change an entity's id, while preserving the parent?

# clone the old_entity and parent as new_entity
new_entity = MyModel(**old_entity.to_dict(), id=new_id, parent=old_entity.parent())

And then, I should be able to do this to replace the old entity with the new one:

new_entity.put()            # save the new entity
old_entity.key.delete()     # delete the old entity 
Community
  • 1
  • 1
Brent Washburne
  • 12,904
  • 4
  • 60
  • 82
  • 1
    You can ref post [copy entity](http://stackoverflow.com/questions/2687724/copy-an-entity-in-google-app-engine-datastore-in-python-without-knowing-property) for copy object. – Sanch Oct 23 '15 at 12:43
  • http://stackoverflow.com/questions/14314344/how-to-copy-all-entities-in-a-kind-in-gae-to-another-kind-without-explicitly-cal – Nicholas Franceschina Oct 28 '15 at 14:48

2 Answers2

2
def clone_entity(e, **extra_args):
   klass = e.__class__
   props = dict((v._code_name, v.__get__(e, klass)) for v in klass._properties.itervalues() if type(v) is not ndb.ComputedProperty)
   props.update(extra_args)
   return klass(**props)

example

b = clone_entity(a, id='new_id_here')
Sanch
  • 137
  • 7
0

@sanch's answer works fine in most cases, but for some reason it will not copy attributes of type ndb.PickleProperty. This modification will work for all attributes, including PickleProperty, and will also accept an optionnal new_class parameter to make a clone of another class.:

def clone_entity(e, **extra_args):
    """
    Clone an ndb entity and return the clone.
    Special extra_args may be used to:
     - request cloned entity to be of a different class (and yet have attributes from original entity)
     - define a specific parent, id or namespace for the cloned entity.
    :param e:  The ndb entity to be cloned.
    :param extra_args: May include special args 'parent', 'id', 'namespace', that will be used when initializing new entity.
            other extra_args, may set values for specific attributes.
    :return: The cloned entity
    """

    if 'new_class' in extra_args:
        klass = extra_args.pop('new_class')
    else:
        klass = e.__class__

    props = dict((v._code_name, v.__get__(e, klass)) for v in klass._properties.itervalues() if type(v) is not ndb.ComputedProperty)
    init_args = dict()

    for arg in ['parent', 'id', 'namespace']:
        if arg in extra_args:
            init_args[arg] = extra_args.pop(arg)

    clone = klass(**init_args)
    props.update(**extra_args)
    clone.populate(**props)
    return clone
patb
  • 1,688
  • 1
  • 17
  • 21