On Jun 4, 2013, at 10:38 AM, Etienne Rouxel <rouxel.etie...@gmail.com> wrote:

> 
> and then:
> 
> UPDATE botany.plant SET taxon_id=NULL WHERE botany.plant.id =  -2147483643
> 
> which fails because NULL is not allowed for taxon_id. So, why do not 
> SQLAlchemy just output this instead?
> 
> UPDATE botany.plant SET taxon_id= -2147483645 WHERE botany.plant.id =  
> -2147483643

if you look in your stack trace, you'll see the word "autoflush" (I adapted 
your excerpt into a full test case to reproduce):

Traceback (most recent call last):
  File "test.py", line 74, in <module>
    plant.taxon = taxon_new  # triggers an IntegrityError
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 
303, in __set__

...

 File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 
824, in fire_replace_event
    value = fn(state, value, previous, initiator or self)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 
1131, in emit_backref_from_scalar_set_event
    passive=PASSIVE_NO_FETCH)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 
638, in append

... 

 File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/strategies.py", line 
585, in _emit_lazyload
    result = q.all()
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/query.py", line 2219, 
in all
    return list(self)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/query.py", line 2330, 
in __iter__
    self.session._autoflush()
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/session.py", line 
1139, in _autoflush
    self.flush()


you can see that the ORM is not getting as far as taxon_new being fully 
assigned.   The assignment is resulting in the backref firing off and leading 
to an assignment on the Taxon.plant side.    The assignment then tries to load 
the existing value for Taxon.plant, which results in an autoflush, which 
results in the integrity error.

There seems to be some unfortunate effect going on, as the issue of backrefs 
loading collections like this was long ago resolved to defer that activity, but 
it appears that when uselist=False is present, this logic no longer takes 
place.  Ticket http://www.sqlalchemy.org/trac/ticket/2741 has been added to 
look into this as this should not be happening.

Anytime a stack trace has "autoflush" in it where you don't want autoflush to 
occur, defer autoflush for those operations like this:

with session.no_autoflush:
    plant.taxon = taxon_new
session.flush()  # optional, emits the UPDATE you're looking for sooner rather 
than later
print plant.taxon is taxon_new




-- 
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to