On Aug 25, 2011, at 10:22 AM, Jaimy Azle wrote:
> On Thursday, August 25, 2011, 7:36:53 PM, Michael Bayer wrote:
>
> Thanks Michael,
>
>> The Session is not usable in the way you're using it inside of
>> after_insert and after_delete - in particular the modifications made
>> to the state of the object that was just inserted will be discarded,
>> and the add() will have no effect as the flush plan cannot be
>> changed in these events.
>
> Still, there is an odd issue here, those mapper event only triggered
> on first instance only.
I would ask why you believe that's true - from what I can tell, you're using
the Session.add() or something as a means to test that the event is triggered,
which as I mentioned will have side effects.
A proper test as below indicates two inserts for Detail, one insert for Master,
as expected:
import collections
total_insert_calls = collections.defaultdict(int)
total_delete_calls = collections.defaultdict(int)
def model_after_insert(mapper, connection, target):
total_insert_calls[mapper.class_] += 1
def model_after_delete(mapper, connection, target):
total_delete_calls[mapper.class_] += 1
...
assert total_insert_calls[Master] == 1
assert total_insert_calls[Detail] == 2
assert not total_delete_calls
script is attached.
>
>>> dt_1 = Detail(1, 1, 'This is detail')
>>> dt_2 = Detail(1, 2, 'This is detail')
>>> session.add(dt_1)
>>> session.add(dt_2)
>>> session.commit() # only the first instance call after_insert
>>> # event, not all
>
>> To modify the Session's flush plan within a flush event, use the
>> before_flush() session event.
>
> How to retrieve affected instances with their state (being inserted,
> updated, or deleted) that belong to a flush operation? for this case I
> need to validate each instance after they were inserted or before they
> were deleted from a persistence storage and adjust some rows from
> another table.
Within before_flush() you work with the session.new, session.dirty, and
session.deleted collections, as well as with attributes.get_history() to look
at individual attribute changes. Any of the versioning examples on the wiki
at http://www.sqlalchemy.org/trac/wiki/UsageRecipes illustrate these techniques.
--
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.
from sqlalchemy import create_engine, event
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker, mapper
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
import collections
total_insert_calls = collections.defaultdict(int)
total_delete_calls = collections.defaultdict(int)
def model_after_insert(mapper, connection, target):
total_insert_calls[mapper.class_] += 1
def model_after_delete(mapper, connection, target):
total_delete_calls[mapper.class_] += 1
event.listen(mapper, 'after_insert', model_after_insert)
event.listen(mapper, 'after_delete', model_after_delete)
class Master(Base):
__tablename__ = 'master'
id = Column(Integer, primary_key=True)
name = Column(String)
total = Column(Integer)
def __init__(self, name):
self.name = name
self.total = 0
class Detail(Base):
__tablename__ = 'detail'
id = Column(Integer, primary_key=True)
master = Column(Integer, primary_key=True)
name = Column(String)
def __init__(self, id, master, name):
self.id = id
self.name = name
self.master = master
klass = Master
Base.metadata.create_all(engine)
session = Session()
master = Master('hello world')
session.add(master)
session.commit()
dt_1 = Detail(1, 1, 'This is detail')
dt_2 = Detail(1, 2, 'This is detail')
session.add(dt_1)
session.add(dt_2)
session.commit()
assert total_insert_calls[Master] == 1
assert total_insert_calls[Detail] == 2
assert not total_delete_calls
master = session.query(Master).filter_by(id = 1).first()
print('total ', master.total)