Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use make_transient() to duplicate an SQLAlchemy mapped object?

I know the question how to duplicate or copy a SQLAlchemy mapped object was asked a lot of times. The answer always depends on the needs or how "duplicate" or "copy" is interpreted. This is a specialized version of the question because I got the tip to use make_transient() for that.

But I have some problems with that. I don't really know how to handle the primary key (PK) here. In my use cases the PK is always autogenerated by SQLA (or the DB in background). But this doesn't happen with a new duplicated object.

The code is a little bit pseudo.

import sqlalchemy as sa
from sqlalchemy.orm.session import make_transient

_engine = sa.create_engine('postgres://...')
_session = sao.sessionmaker(bind=_engine)()


class MachineData(_Base):
    __tablename__ = 'Machine'    
    _oid = sa.Column('oid', sa.Integer, primary_key=True)


class TUnitData(_Base):
    __tablename__ = 'TUnit'
    _oid = sa.Column('oid', sa.Integer, primary_key=True)
    _machine_fk = sa.Column('machine', sa.Integer, sa.ForeignKey('Machine.oid'))
    _machine = sao.relationship("MachineData")

    def __str__(self):
        return '{}.{}: oid={}(hasIdentity={}) machine={}(fk={})' \
        .format(type(self), id(self),
                self._oid, has_identity(self),
                self._machine, self._machine_fk)


if __name__ == '__main__':
    # any query resulting in one persistent object
    obj = GetOneMachineDataFromDatabase()

    # there is a valid 'oid', has_identity == True
    print(obj)

    # should i call expunge() first?

    # remove the association with any session
    # and remove its “identity key”
    make_transient(obj)

    # 'oid' is still there but has_identity == False
    print(obj)

    # THIS causes an error because the 'oid' still exsits
    # and is not new auto-generated (what should happen in my
    # understandings)
    _session.add(obj)
    _session.commit()
like image 373
buhtz Avatar asked May 17 '15 12:05

buhtz


People also ask

What is _sa_instance_state in SQLAlchemy?

_sa_instance_state is a non-database-persisted value used by SQLAlchemy internally (it refers to the InstanceState for the instance. While not directly relevant to this section, if we want to get at it, we should use the inspect() function to access it).

What is Sessionmaker in SQLAlchemy?

Session in SQLAlchemy ORM However, to standardize how sessions are configured and acquired, the sessionmaker class is normally used to create a top-level Session configuration which can then be used throughout an application without the need to repeat the configurational arguments.

What is identity map in SQLAlchemy?

identity map. A mapping between Python objects and their database identities. The identity map is a collection that's associated with an ORM Session object, and maintains a single instance of every database object keyed to its identity.

What function creates a Session object in SQLAlchemy?

The sessionmaker factory generates new Session objects when called, creating them given the configurational arguments established here.


1 Answers

After making a object instance transient you have to remove its object-id. Without an object-id you can add it again to the database which will generate a new object-id for it.

if __name__ == '__main__':
    # the persistent object with an identiy in the database
    obj = GetOneMachineDataFromDatabase()

    # make it transient
    make_transient(obj)
    # remove the identiy / object-id
    obj._oid = None
    # adding the object again generates a new identiy / object-id
    _session.add(obj)
    # this include a flush() and create a new primary key
    _session.commit()
like image 174
buhtz Avatar answered Oct 13 '22 00:10

buhtz