On Jun 4, 2013, at 10:38 AM, Etienne Rouxel <[email protected]> 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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.