On Aug 27, 2014, at 5:31 PM, Chad Dombrova <chad...@gmail.com> wrote:

> Thanks for the quick response Michael.
> 
> One more question, if you don't mind:
> 
> I updated my gist to demonstrate this problem: 
> https://gist.github.com/chadrik/08617b6ed4d9cbacd93c
> 
> To sum it up, I added a one-to-many relationships between Books and Chapters, 
> but the relationships which show items added in their history within the 
> after_flush event vary depending on how the update is performed.
> 
> For example, if the relationship is updated through its backref, like this:
> 
>     book1.chapters.append(Chapter(title='Intro to Book1'))

> 
> 
> 
> then relationships on both side show values added in their history:
> 
> 
> 
> Chapter('Intro to Book1')
>  'book' added: [Book(1)]
> Book(1)
>  'chapters' added: [Chapter('Intro to Book1')]
> 
> 
> but if the relationship is updated like this:
> 
> 
> 
>     Chapter(title='Intro to Book2', book=book2)
> 
> 
> 
> then only one side shows that a value was added:
> 
> 
> 
> Chapter('Intro to Book2')
>  'book' added: [Book(2)]
> Book(2)
>  no relationships updated
> 
> 
> in this latter case, is there a reliable way to know what items have been 
> added to Book.chapters within the after_flush event?

this is true.  if you update an item on the many-to-one side, and the o2m side 
isn't loaded, SQLAlchemy doesn't touch it, because it would mean emitting a 
load for the book1.chapters collection.    Chapter(book=book2) doesn't imply 
any change to Book on the database side.   The history can't show "what 
changed" without loading in the collection to compare.

But your code isn't working because somehow you've dug in and bypassed all the 
public history APIs to find one that is internal to the flush context and is 
actually cached.  If you want to see book1.chapters changed, you'd have to emit 
a load for it which means fetching the history fully.    When you're looking at 
state.attrs you can choose between ".history" and ".load_history()", the latter 
emits the load: 
http://docs.sqlalchemy.org/en/rel_0_9/orm/internals.html?highlight=load_history#sqlalchemy.orm.state.AttributeState.load_history.
  Both call into the same resources that the public function 
attributes.load_history() calls into, sending a different value for "passive".

this function also converts from "state", so here's the code:

        for prop in state.mapper.relationships:
            history = state.attrs[prop.key].load_history()
            added, unchanged, deleted = history

            if added:
                updated = True
                print " %r added: %r" % (prop.key, added)

output at the bottom:

Chapter('Intro to Book1')
 'book' added: [Book(1)]
Book(2)
 'chapters' added: [Chapter('Intro to Book2')]
Book(1)
 'chapters' added: [Chapter('Intro to Book1')]
Chapter('Intro to Book2')
 'book' added: [Book(2)]





> 
> thanks,
> chad
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to