views:

300

answers:

1

Hi everyone!
I'm trying to automatically build a shallow copy of a SA-mapped object.. At the moment my function is just:

newobj = src.__class__()
for prop in class_mapper(src.__class__).iterate_properties:
    setattr(newobj, prop.key, getattr(src, prop.key))

but I'm having troubles with lazy relations... Obviously getattr triggers the lazy loading, but since I don't need their values right away, I'd like to just copy the "this should be lazy loaded"-state of the attribute... Is this possible?

Edit: I need this for a "data logging" system.. That is, whenever someone updates a persisted entity, I have to generate a new record and then mark the old one as such.
In order to do this I create a shallow copy of the entity (so SQLA issues an INSERT instead of an UPDATE) and work from there.. The system works quite nicely (it's been in production use for months) but now I'd like to enhance it so that it won't need that all the relations get lazy-loaded first..

+1  A: 

What you need is to copy column properties only, which can be easily filtered using isinstance(prop, sqlalchemy.orm.ColumnProperty). Note, that you HAVE to copy externally stored relations (all many-to-many), since there is no columns corresponding to them in the main table. This can't be done with high-level interface without lazy-loading, so I'd prefer to accept this trade-off. Many-to-many relations can be determined with isinstance(prop, RelationProperty) and prop.secondary test. The resulting code will look like the following:

from sqlalchemy.orm import object_mapper, ColumnProperty, RelationProperty

newobj = type(src)()
for prop in object_mapper(src).iterate_properties:
    if (isinstance(prop, ColumnProperty) or
        isinstance(prop, RelationProperty) and prop.secondary):
    setattr(newobj, prop.key, getattr(src, prop.key))

Also note, that SQLAlchemy is designed to maintain single object loaded for each identity, while your copy breaks this when identity (primary key) properties are copied too, but this is probably not your case if your are storing with new (versioned) identifier.

Denis Otkidach
Ok editing the question.. :)
Joril