Commits

Mike Bayer  committed a6b30bf

- [feature] The after_attach event is now
emitted after the object is established
in Session.new or Session.identity_map
upon Session.add(), Session.merge(),
etc., so that the object is represented
in these collections when the event
is called. [ticket:2464]

  • Participants
  • Parent commits 4087e6f

Comments (0)

Files changed (3)

     "is_remove" when this flag is used.
     also in 0.7.7.
 
+  - [feature] The after_attach event is now
+    emitted after the object is established
+    in Session.new or Session.identity_map
+    upon Session.add(), Session.merge(), 
+    etc., so that the object is represented
+    in these collections when the event 
+    is called. [ticket:2464]
+
   - [bug] Fixed bug whereby polymorphic_on
     column that's not otherwise mapped on the 
     class would be incorrectly included

File lib/sqlalchemy/orm/session.py

                 "Object '%s' already has an identity - it can't be registered "
                 "as pending" % mapperutil.state_str(state))
 
-        self._attach(state)
         if state not in self._new:
             self._new[state] = state.obj()
             state.insert_order = len(self._new)
+        self._attach(state)
 
     def _update_impl(self, state):
         if (self.identity_map.contains_state(state) and
                 "function to send this object back to the transient state." %
                 mapperutil.state_str(state)
             )
-        self._attach(state)
         self._deleted.pop(state, None)
         self.identity_map.add(state)
+        self._attach(state)
 
     def _save_or_update_impl(self, state):
         if state.key is None:

File test/orm/test_events.py

 from sqlalchemy.orm import mapper, relationship, \
     create_session, class_mapper, \
     Mapper, column_property, \
-    Session, sessionmaker
+    Session, sessionmaker, attributes
 from sqlalchemy.orm.instrumentation import ClassManager
 from test.lib.testing import eq_
 from test.lib import fixtures
         eq_(canary, ['before_commit', 'before_flush', 'after_flush',
                        'after_flush_postexec', 'after_commit'])
 
+    def test_state_after_attach(self):
+        User, users = self.classes.User, self.tables.users
+        sess = Session()
+
+        @event.listens_for(sess, "after_attach")
+        def listener(session, inst):
+            state = attributes.instance_state(inst)
+            if state.key:
+                assert session.identity_map[state.key] is inst
+            else:
+                assert inst in session.new
+
+        mapper(User, users)
+        u= User(name='u1')
+        sess.add(u)
+        sess.flush()
+        sess.expunge(u)
+        sess.add(u)
+
     def test_standalone_on_commit_hook(self):
         sess, canary = self._listener_fixture()
         sess.commit()