Would you like to get a "copy" that is simply the same object with the
same identity, just as present in another session (in which case use
merge()) ?
Or would you like to get a "copy" that is a transient (no database
identity) copy of that object, with all attributes except primary key
attributes copied over ? ( in which case you'd use a copy constructor
which possibly uses mapping metadata to traverse ) ?
the practice shows there are attributes
- which u dont want to copy at all (dontcopy=list e.g. timestamps),
- which u dont want to copy in depth (dontcopyme=true, e.g. refs to
external things),
- which u dont want the particular op to copy - e.g. because have
been copied/changed by hand (dontcopy_now=list).
There also the case of explicit m2m assoc_objects which are handled
differently of all else.
so it has to be some manual copy, or a very special setup of
pickle-protocol-controls.
seems this is a common requirement, so i may put mine somewhere in
dbcook/.
have fun
svil
> Michael,
>
> Thanks for your reply.
>
> The use case is configuration management.
>
> We have complex (SQLAlchemy) objects with many relationships which
> we wish to up-version, i.e. we want an exact persistent copy
> (attribute values and relationships) of the original object, but
> with a different identity, which we will then modify.
>
> The original object and all its relationships should remain
> unchanged (other than a relationship to its successor version).
>
> We would want the copied object and all its relationships saved to
> the database before making changes to it.
You'd build a copy function of your own which iterates through
attributes and creates new instances. How you go about locating the
attributes to be copied depends on if you want only SQLAlchemy-
instrumented attributes, or other attributes as well which are not
known to SQLAlchemy.
To get a list of all SQLAlchemy attributes for a class, use this
expression:
[p.key for p in class_mapper(class).iterate_properties]
you might want to exclude primary key mappings:
pk_keys = set([c.key for c in class_mapper(class).primary_key])
[p.key for p in class_mapper(class).iterate_properties if p.key not in
pk_keys]
the value for each attribute can be retrieved from an instance using
getattr(instance, key), and you can construct new instances without
calling __init__ by saying class.__new__(class).
maybe someone here can flesh this out for me, im a little busy today....
i'll be doing it anyway.. maybe after a day or two.
some more details for above:
- references *toone are the props with p.use_list = False
- manytomany when prop.direction==orm.interfaces.MANYTOMANY
- explicit m2m has to be determined manualy
btw i've run into interesting case today, where some attribute (the
object_identity) needs to be shallow-copied if the copy is to be used
as another version of same object, or not be copied at all if it's to
be used for another object. but i guess this would be postprocessing
as the copy() wouldnot know such things.
ah yes, another related thing we're doing is a ORM-level dump, e.g.
like pickle-the-whole-or-partial-object-storage into lists/dict/sets
etc - for simple object replication. might be interesting to someone.
svil
Whoops - occasionally a session autoflush can break the function above - a better version delays the session.add() calls until the relationships have been built: