]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed issue where post_update on a many-to-one relationship would
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 2 Dec 2015 17:13:57 +0000 (12:13 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 2 Dec 2015 17:13:57 +0000 (12:13 -0500)
fail to emit an UPDATE in the case where the attribute were set to
None and not previously loaded.
fixes #3599

doc/build/changelog/changelog_10.rst
lib/sqlalchemy/orm/dependency.py
test/orm/test_cycles.py

index ffc2c344682c13917952a0ae6c1c8a7b1a451b9c..6fc75b18b17cd13f2411263d3ec6e2c0e2ac84d8 100644 (file)
 .. changelog::
     :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
index d8989939b6e0814826c50e5de310447d4e0334c2..f3325203e655c4055fd0ee1fbfa103935e49471c 100644 (file)
@@ -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:
index 56386e8d2b676f9b34f19981d7c4ecdf521c0e1e..b5c1b646729a3c76512be04bbeb2e915a7aa7de6 100644 (file)
@@ -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.