summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-12-02 12:13:57 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-12-02 12:13:57 -0500
commit935bc34dc50d5e4bdf181a8287d6e4cdbde073d0 (patch)
treee9eba984da6f31639918eb1dfe0e21253995b6c9
parent9695faf32981406b12a6468b98d5c9b673f8e219 (diff)
downloadsqlalchemy-935bc34dc50d5e4bdf181a8287d6e4cdbde073d0.tar.gz
- Fixed issue where post_update on a many-to-one relationship would
fail to emit an UPDATE in the case where the attribute were set to None and not previously loaded. fixes #3599
-rw-r--r--doc/build/changelog/changelog_10.rst9
-rw-r--r--lib/sqlalchemy/orm/dependency.py8
-rw-r--r--test/orm/test_cycles.py35
3 files changed, 48 insertions, 4 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index ffc2c3446..6fc75b18b 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -19,6 +19,15 @@
:version: 1.0.10
.. change::
+ :tags: bug, orm
+ :tickets: 3599
+ :versions: 1.1.0b1
+
+ Fixed issue where post_update on a many-to-one relationship would
+ fail to emit an UPDATE in the case where the attribute were set to
+ None and not previously loaded.
+
+ .. change::
:tags: bug, sql, postgresql
:tickets: 3598
:versions: 1.1.0b1
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py
index d8989939b..f3325203e 100644
--- a/lib/sqlalchemy/orm/dependency.py
+++ b/lib/sqlalchemy/orm/dependency.py
@@ -303,9 +303,9 @@ class DependencyProcessor(object):
set
)
- def _post_update(self, state, uowcommit, related):
+ def _post_update(self, state, uowcommit, related, is_m2o_delete=False):
for x in related:
- if x is not None:
+ if not is_m2o_delete or x is not None:
uowcommit.issue_post_update(
state,
[r for l, r in self.prop.synchronize_pairs]
@@ -740,7 +740,9 @@ class ManyToOneDP(DependencyProcessor):
self.key,
self._passive_delete_flag)
if history:
- self._post_update(state, uowcommit, history.sum())
+ self._post_update(
+ state, uowcommit, history.sum(),
+ is_m2o_delete=True)
def process_saves(self, uowcommit, states):
for state in states:
diff --git a/test/orm/test_cycles.py b/test/orm/test_cycles.py
index 56386e8d2..b5c1b6467 100644
--- a/test/orm/test_cycles.py
+++ b/test/orm/test_cycles.py
@@ -10,7 +10,7 @@ from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.testing.schema import Table, Column
from sqlalchemy.orm import mapper, relationship, backref, \
create_session, sessionmaker
-from sqlalchemy.testing import eq_
+from sqlalchemy.testing import eq_, is_
from sqlalchemy.testing.assertsql import RegexSQL, CompiledSQL, AllOf
from sqlalchemy.testing import fixtures
@@ -816,6 +816,39 @@ class OneToManyManyToOneTest(fixtures.MappedTest):
{'id': b4.id}])
)
+ def test_post_update_m2o_detect_none(self):
+ person, ball, Ball, Person = (
+ self.tables.person,
+ self.tables.ball,
+ self.classes.Ball,
+ self.classes.Person)
+
+ mapper(Ball, ball, properties={
+ 'person': relationship(
+ Person, post_update=True,
+ primaryjoin=person.c.id == ball.c.person_id)
+ })
+ mapper(Person, person)
+
+ sess = create_session(autocommit=False, expire_on_commit=True)
+ sess.add(Ball(person=Person()))
+ sess.commit()
+ b1 = sess.query(Ball).first()
+
+ # needs to be unloaded
+ assert 'person' not in b1.__dict__
+ b1.person = None
+
+ self.assert_sql_execution(
+ testing.db,
+ sess.flush,
+ CompiledSQL(
+ "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id",
+ lambda ctx: {'person_id': None, 'ball_id': b1.id})
+ )
+
+ is_(b1.person, None)
+
class SelfReferentialPostUpdateTest(fixtures.MappedTest):
"""Post_update on a single self-referential mapper.