diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-12-02 12:13:57 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-12-02 12:13:57 -0500 |
commit | 935bc34dc50d5e4bdf181a8287d6e4cdbde073d0 (patch) | |
tree | e9eba984da6f31639918eb1dfe0e21253995b6c9 | |
parent | 9695faf32981406b12a6468b98d5c9b673f8e219 (diff) | |
download | sqlalchemy-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.rst | 9 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/dependency.py | 8 | ||||
-rw-r--r-- | test/orm/test_cycles.py | 35 |
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. |