[Sqlalchemy-tickets] Issue #3635: Explicitly set column value overriden by older initialization val
Brought to you by:
zzzeek
|
From: Torsten L. <iss...@bi...> - 2016-01-21 22:13:40
|
New issue 3635: Explicitly set column value overriden by older initialization value of relationship property https://bitbucket.org/zzzeek/sqlalchemy/issues/3635/explicitly-set-column-value-overriden-by Torsten Landschoff: 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: 1. I create a mapped instance and the ``__init__`` initializes a few relationship properties to `None`, making my IDE happy that everything is set up in `__init__`. 2. The foreign key column underlying the relationship is explicitly set to a specific value. 3. 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? |