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" <[email protected]> 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
>> > <[email protected]>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 <[email protected]> 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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---