- edited description
Explicitly set column value overriden by older initialization value of relationship property
I lately updated my application from SQLAlchemy 0.7.10 to 1.0.11 and expected no problems (the reason for the late update was PyInstaller, which did not manage to build an executable with a new SQLAlchemy).
However, after a while of testing I ran into the following behaviour in SA 1.0.1:
- I create a mapped instance and the
__init__
initializes a few relationship properties toNone
, making my IDE happy that everything is set up in__init__
. - The foreign key column underlying the relationship is explicitly set to a specific value.
- During commit I run into
IntegrityError
, because the column value is reset to NULL.
The attached example relation_overrides_column.py
illustrates the problem. With SA 0.7.8 I got the expected output:
$ pip install sqlalchemy==0.7.10
Collecting sqlalchemy==0.7.10
Installing collected packages: sqlalchemy
Successfully installed sqlalchemy-0.7.10
$ python relation_overrides_column.py
[Schema creation commands]
2016-01-21 23:07:40,690 INFO sqlalchemy.engine.base.Engine COMMIT
2016-01-21 23:07:40,692 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2016-01-21 23:07:40,692 INFO sqlalchemy.engine.base.Engine INSERT INTO customer (name) VALUES (?)
2016-01-21 23:07:40,693 INFO sqlalchemy.engine.base.Engine ('William',)
2016-01-21 23:07:40,693 INFO sqlalchemy.engine.base.Engine COMMIT
2016-01-21 23:07:40,693 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2016-01-21 23:07:40,694 INFO sqlalchemy.engine.base.Engine INSERT INTO "order" (customer_name) VALUES (?)
2016-01-21 23:07:40,694 INFO sqlalchemy.engine.base.Engine ('William',)
2016-01-21 23:07:40,694 INFO sqlalchemy.engine.base.Engine COMMIT
compared to SA 1.0.11:
$ pip install sqlalchemy==1.0.11
Collecting sqlalchemy==1.0.11
Installing collected packages: sqlalchemy
Found existing installation: SQLAlchemy 0.7.10
Uninstalling SQLAlchemy-0.7.10:
Successfully uninstalled SQLAlchemy-0.7.10
Successfully installed sqlalchemy-1.0.11
$ python relation_overrides_column.py
[Test casting and DDL setup]
2016-01-21 23:09:16,537 INFO sqlalchemy.engine.base.Engine COMMIT
2016-01-21 23:09:16,541 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2016-01-21 23:09:16,542 INFO sqlalchemy.engine.base.Engine INSERT INTO customer (name) VALUES (?)
2016-01-21 23:09:16,542 INFO sqlalchemy.engine.base.Engine ('William',)
2016-01-21 23:09:16,543 INFO sqlalchemy.engine.base.Engine COMMIT
2016-01-21 23:09:16,543 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2016-01-21 23:09:16,544 INFO sqlalchemy.engine.base.Engine INSERT INTO "order" (customer_name) VALUES (?)
2016-01-21 23:09:16,544 INFO sqlalchemy.engine.base.Engine (None,)
2016-01-21 23:09:16,545 INFO sqlalchemy.engine.base.Engine ROLLBACK
Traceback (most recent call last):
File "relation_overrides_column.py", line 37, in <module>
session.commit()
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 813, in commit
self.transaction.commit()
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 392, in commit
self._prepare_impl()
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 372, in _prepare_impl
self.session.flush()
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2027, in flush
self._flush(objects)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2145, in _flush
transaction.rollback(_capture_exception=True)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2109, in _flush
flush_context.execute()
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
rec.execute(self)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
uow
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 174, in save_obj
mapper, table, insert)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 800, in _emit_insert_statements
execute(statement, params)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 914, in execute
return meth(self, multiparams, params)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
compiled_sql, distilled_params
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1146, in _execute_context
context)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1341, in _handle_dbapi_exception
exc_info
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 200, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1139, in _execute_context
context)
File "/opt/dynasdk/loco2-precise/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 450, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (pysqlite2.dbapi2.IntegrityError) NOT NULL constraint failed: order.customer_name [SQL: u'INSERT INTO "order" (customer_name) VALUES (?)'] [parameters: (None,)]
In this example it is easy to fix by not setting the relation self.customer = None
in __init__
, but I basically have to change all my classes to make sure that they never set a relationship if column access might happen later to write the actual value.
Any thoughts on this? Was this by accident or a deliberate change in behaviour?
Comments (2)
-
reporter -
repo owner - changed status to closed
this is a 1.0 behavioral change which is described in http://docs.sqlalchemy.org/en/rel_1_0/changelog/migration_10.html#migration-3060
- Log in to comment