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.