25

I want to duplicate a model instance (row) in SQLAlchemy using the orm. My first thought was to do this:

i = session.query(Model)
session.expunge(i)

old_id = i.id
i.id = None
session.add(i)
session.flush()
print i.id #New ID

However, apparently the detached object still "remembers" what id it had, even though I set the id to None while it was detached. Thus, session.flush() tries to execute an UPDATE changing the primary key to null.

Is this expected behavior? How can I remove the 'memory' of this attribute, and just treat the detached object as a new object upon re-adding it to the session? How, in general, does one clone an SQLAlchemy model instance?

Zoran Pavlovic
  • 1,166
  • 2
  • 23
  • 38
EB.
  • 3,383
  • 5
  • 31
  • 43

2 Answers2

43

this case is available using the make_transient() helper function:

inst = session.query(Model).first()
session.expunge(inst)

make_transient(inst)
inst.id = None
session.add(inst)
session.flush()
print inst.id #New ID
Stephen Fuhry
  • 12,624
  • 6
  • 56
  • 55
zzzeek
  • 72,307
  • 23
  • 193
  • 185
  • 4
    What's the proper way to copy relationships as well, @zzzeek? – jmagnusson Dec 15 '14 at 17:55
  • I too am interested in something similar. I am interested in cloning an entity (a row), together with all its 'child' entities (rows in other tables, with foreign keys pointing at this row), and attaching this new duplicate row and its duplicate children to a new parent entity by way of a different foreign key in the new duplicate row (but without affecting the existing entity and its child entities). I can see this partial answer on another question on SO: http://stackoverflow.com/questions/20112850/sqlalchemy-clone-table-row-with-relations?lq=1 – Soferio Jan 01 '15 at 06:50
1
def duplicate(self):
    arguments = dict()
    for name, column in self.__mapper__.columns.items():
        if not (column.primary_key or column.unique):
            arguments[name] = getattr(self, name)
    return self.__class__(**arguments)