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
-~----------~----~----~----~------~----~------~--~---

Reply via email to