OK in fact this can possibly be implemented if the "initiator" passed during attribute mutation operations consisted of not just an AttributeImpl but also a target instance, so that append/remove/set operations can have the information they need continue down the chain of events without exiting prematurely. Such as this test below:
from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) stuff = relation("Stuff", backref="parent") class Stuff(Base): __tablename__ = 'stuff' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('parent.id')) p1 = Parent() p2 = Parent() s1 = Stuff() p1.stuff.append(s1) p2.stuff.append(s1) assert s1.parent is p2 assert s1 not in p1.stuff assert s1 in p2.stuff can be made to pass if we say this: Index: lib/sqlalchemy/orm/attributes.py =================================================================== --- lib/sqlalchemy/orm/attributes.py (revision 5901) +++ lib/sqlalchemy/orm/attributes.py (working copy) @@ -679,9 +679,6 @@ collection.append_with_event(value, initiator) def remove(self, state, value, initiator, passive=PASSIVE_OFF): - if initiator is self: - return - collection = self.get_collection(state, passive=passive) if collection is PASSIVE_NORESULT: self.fire_remove_event(state, value, initiator) so some more complete way of not exiting the event loop too soon would need to be implemented. Jason, any comments on this ? jean-philippe dutreve wrote: > > It would be fine/safe that accountA has entry removed BEFORE any > reload (with explicit refresh/expire/commit). I can't remember, but a > previous version of SA had this behavior. > > On Apr 6, 4:42 pm, "Michael Bayer" <mike...@zzzcomputing.com> wrote: >> im slightly confused. the backref should be automatically reparenting, >> not sure if ordering_list interferes with that, but in any case after >> you >> flush()/expire() or commit(), it will definitely happen since all >> collections will load fresh. >> >> Mike Conley wrote: >> > So, we would like SA to have some kind of operation like >> "reparent_item()" >> > that would move an object from one relation to another. >> > It seems to me that this is is better handled as a piece of >> application >> > business logic. In this case, provide a "move_entry()" function that >> > properly encapsulates inserting and removing the entry in a single >> > operation. I can imagine that there would be many variations on >> business >> > rules for moving an item that would be difficult to encapsulate in a >> > common >> > operation within SA. >> >> > -- >> > Mike Conley >> >> > On Mon, Apr 6, 2009 at 2:10 AM, jean-philippe dutreve >> > <jdutr...@gmail.com>wrote: >> >> >> Currently, I use accountA.remove(entry) and I have rewritten insort >> to >> >> bypass the bug you say. >> >> >> So, AFAIK, whereas an entry has only one account (via >> >> entry.account_id), SA can't remove the first relation. >> >> It's dangerous, because if developer forget to remove the first >> >> relation, the entry is contained in 2 accounts temporaly. >> >> It can lead to false computation (when summing balance for instance). >> >> >> On 5 avr, 22:03, jason kirtland <j...@discorporate.us> wrote: >> >> > jean-philippe dutreve wrote: >> >> > > Hi all, >> >> >> > > I wonder if SA can handle this use case: >> >> >> > > An Account can contain Entries ordered by 'position' attribute. >> >> >> > > mapper(Account, table_accounts, properties = dict( >> >> > > entries = relation(Entry, lazy=True, >> >> collection_class=ordering_list >> >> > > ('position'), >> >> > > order_by=[table_entries.c.position], >> >> > > passive_deletes='all', cascade='save-update', >> >> > > backref=backref('account', lazy=False), >> >> > > ), >> >> > > )) >> >> >> > > I'd like to move an entry from accountA to accountB and let SA >> >> remove >> >> > > the link between the entry and accountA: >> >> >> > > entry = accountA.entries[0] >> >> > > insort_right(accountB.entries, entry) >> >> > > assert not entry in accountA.entries # false, entry is >> still >> >> in >> >> > > accountA !!!! >> >> >> > > It is possible? >> >> >> > Try removing the entry from accountA: >> >> >> > entry = accountA.pop(0) >> >> > ... >> >> >> > Also beware that bisect insort has a bug that prevents it from >> working >> >> > properly with list subclasses like ordering_list (or any SA >> list-based >> >> > collection). I think it's fixed in Python 3.0, not sure if the fix >> >> was >> >> > backported to 2.x. > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---