[sqlalchemy] Re: Changing a value linked with a one-to-one relationship

2013-06-05 Thread Etienne Rouxel
Hello Michael

Sorry for the late reply.

So, below is my full stack trace:

Traceback (most recent call last):
  File 
/Users/foobar/Developpement/nursery_project/applications/nurserydb/utils_scripts/test2.py,
 
line 64, in module
plant.taxon = taxon_new  # triggers an IntegrityError
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/attributes.py, 
line 303, in __set__
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/attributes.py, 
line 804, in set
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/attributes.py, 
line 824, in fire_replace_event
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/attributes.py, 
line 1131, in emit_backref_from_scalar_set_event
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/attributes.py, 
line 638, in append
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/attributes.py, 
line 788, in set
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/attributes.py, 
line 613, in get
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/strategies.py, 
line 524, in _load_for_state
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/strategies.py, 
line 585, in _emit_lazyload
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/query.py, line 
2104, in all
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/query.py, line 
2215, in __iter__
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/session.py, line 
1138, in _autoflush
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/session.py, line 
1817, in flush
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/session.py, line 
1935, in _flush
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/util/langhelpers.py, 
line 58, in __exit__
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/session.py, line 
1899, in _flush
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/unitofwork.py, 
line 372, in execute
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/unitofwork.py, 
line 525, in execute
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/persistence.py, 
line 58, in save_obj
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/orm/persistence.py, 
line 491, in _emit_update_statements
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/engine/base.py, line 
662, in execute
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/engine/base.py, line 
761, in _execute_clauseelement
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/engine/base.py, line 
874, in _execute_context
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/engine/base.py, line 
1024, in _handle_dbapi_exception
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/util/compat.py, line 
163, in raise_from_cause
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/engine/base.py, line 
867, in _execute_context
  File build/bdist.macosx-10.6-x86_64/egg/sqlalchemy/engine/default.py, 
line 324, in do_execute
sqlalchemy.exc.IntegrityError: (IntegrityError) null value in column 
taxon_id violates not-null constraint
 'UPDATE botany.plant SET taxon_id=%(taxon_id)s WHERE botany.plant.id = 
%(botany_plant_id)s' {'taxon_id': None, 'botany_plant_id': -2147483643}


I guess it correspond to what you mentioned.

I have tried to use what you told :

with session.no_autoflush:
plant.taxon = taxon_new

...and it works fine.

But the thing is that I don't need it in case I comment out the line :

taxon_old = session.query(Taxon).get(-2147483634)

and the test:

print plant.taxon is taxon_old  # True


It seems that the problems occurs because the taxon_old is already loaded 
in the identity map so the taxon.plant of the already loaded taxon_old must 
be changed to reflect the change made by the below line:

plant.taxon = taxon_new  # triggers an IntegrityError

This is totally understandable.

However, I get confused by SQLAlchemy trying to set taxon_id to NULL or 
even worse, by SQLAlchemy trying to delete the plant if I configure a 
cascade='all, delete-orphan' on the backref side of the relationship. I 
understand that it might not be easy for SQLAlchemy to understand what I 
am trying to do, but the fact that I end up with two different results 
depending on whether or not taxon_old is previously loaded is confusing.


Anyway, SQLAlchemy is still very impressive and never ceases to amaze me 
every day I discover new features. Thank you for that.



Le mardi 4 juin 2013 16:38:30 UTC+2, Etienne Rouxel a écrit :

 Hello

 I would like to change a value in a one-to-one relationship but I cannot 
 because of some actions that SQLAlchemy try to do, and I don't know why.
 Here is my simplified code :

 # -*- coding: utf-8 -*-
 from sqlalchemy import *
 from sqlalchemy.orm import *
 from sqlalchemy.ext.declarative import declarative_base

 Base = declarative_base()

 _taxon_table = Table('taxon', Base.metadata,
 Column('id', Integer, primary_key=True),
 schema='botany'
 )

 _foliagetype_table = Table('foliagetype', Base.metadata,
 

Re: [sqlalchemy] Re: Changing a value linked with a one-to-one relationship

2013-06-05 Thread Michael Bayer

On Jun 5, 2013, at 3:52 AM, Etienne Rouxel rouxel.etie...@gmail.com wrote:

 
 However, I get confused by SQLAlchemy trying to set taxon_id to NULL or even 
 worse,

please keep in mind that this was within an autoflush, in between where the 
state of your object graph in memory was complete.  If the flush were to 
succeed, upon the next flush the row would be updated again to the correct 
value.   This is why its important that autoflush run within a transaction.


 by SQLAlchemy trying to delete the plant if I configure a cascade='all, 
 delete-orphan' on the backref side of the relationship. I understand that it 
 might not be easy for SQLAlchemy to understand what I am trying to do, but 
 the fact that I end up with two different results depending on whether or not 
 taxon_old is previously loaded is confusing.

one-to-one relationships have problems in this area, and I can also show you 
versions of your test where a single Taxon gets more than one Plant assigned to 
it, which would then return more than one row for that relationship (SQLAlchemy 
emits a warning when this condition is detected).That's really the main 
concern in this area - SQLAlchemy's load in this case is to detect this 
condition but it can be defeated.




-- 
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.