diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-11-19 19:16:26 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-11-19 19:16:26 -0500 |
| commit | 63508b82cd5710c660383bcac5fcfd3bb6af83c1 (patch) | |
| tree | d1d37de872d048d2beff170dac5324394ec58e99 /test | |
| parent | 452ce0c2e7fae13a569341cbbe6f3a988c0c6360 (diff) | |
| download | sqlalchemy-63508b82cd5710c660383bcac5fcfd3bb6af83c1.tar.gz | |
- The ``viewonly`` flag on :func:`.relationship` will now prevent
attribute history from being written on behalf of the target attribute.
This has the effect of the object not being written to the
Session.dirty list if it is mutated. Previously, the object would
be present in Session.dirty, but no change would take place on behalf
of the modified attribute during flush. The attribute still emits
events such as backref events and user-defined events and will still
receive mutations from backrefs. [ticket:2833]
Diffstat (limited to 'test')
| -rw-r--r-- | test/orm/test_relationships.py | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/test/orm/test_relationships.py b/test/orm/test_relationships.py index 4cd278e16..717f136c0 100644 --- a/test/orm/test_relationships.py +++ b/test/orm/test_relationships.py @@ -14,6 +14,7 @@ from sqlalchemy.testing import eq_, startswith_, AssertsCompiledSQL, is_ from sqlalchemy.testing import fixtures from test.orm import _fixtures from sqlalchemy import exc +from sqlalchemy import inspect class _RelationshipErrors(object): def _assert_raises_no_relevant_fks(self, fn, expr, relname, @@ -1516,6 +1517,117 @@ class TypedAssociationTable(fixtures.MappedTest): assert t3.count().scalar() == 1 +class ViewOnlyHistoryTest(fixtures.MappedTest): + @classmethod + def define_tables(cls, metadata): + Table("t1", metadata, + Column('id', Integer, primary_key=True, + test_needs_autoincrement=True), + Column('data', String(40))) + Table("t2", metadata, + Column('id', Integer, primary_key=True, + test_needs_autoincrement=True), + Column('data', String(40)), + Column('t1id', Integer, ForeignKey('t1.id'))) + + def _assert_fk(self, a1, b1, is_set): + s = Session(testing.db) + s.add_all([a1, b1]) + s.flush() + + if is_set: + eq_(b1.t1id, a1.id) + else: + eq_(b1.t1id, None) + + return s + + def test_o2m_viewonly_oneside(self): + class A(fixtures.ComparableEntity): + pass + class B(fixtures.ComparableEntity): + pass + + mapper(A, self.tables.t1, properties={ + "bs": relationship(B, viewonly=True, + backref=backref("a", viewonly=False)) + }) + mapper(B, self.tables.t2) + + a1 = A() + b1 = B() + a1.bs.append(b1) + assert b1.a is a1 + assert not inspect(a1).attrs.bs.history.has_changes() + assert inspect(b1).attrs.a.history.has_changes() + + sess = self._assert_fk(a1, b1, True) + + a1.bs.remove(b1) + assert a1 not in sess.dirty + assert b1 in sess.dirty + + def test_m2o_viewonly_oneside(self): + class A(fixtures.ComparableEntity): + pass + class B(fixtures.ComparableEntity): + pass + + mapper(A, self.tables.t1, properties={ + "bs": relationship(B, viewonly=False, + backref=backref("a", viewonly=True)) + }) + mapper(B, self.tables.t2) + + a1 = A() + b1 = B() + b1.a = a1 + assert b1 in a1.bs + assert inspect(a1).attrs.bs.history.has_changes() + assert not inspect(b1).attrs.a.history.has_changes() + + sess = self._assert_fk(a1, b1, True) + + a1.bs.remove(b1) + assert a1 in sess.dirty + assert b1 not in sess.dirty + + def test_o2m_viewonly_only(self): + class A(fixtures.ComparableEntity): + pass + class B(fixtures.ComparableEntity): + pass + + mapper(A, self.tables.t1, properties={ + "bs": relationship(B, viewonly=True) + }) + mapper(B, self.tables.t2) + + a1 = A() + b1 = B() + a1.bs.append(b1) + assert not inspect(a1).attrs.bs.history.has_changes() + + self._assert_fk(a1, b1, False) + + def test_m2o_viewonly_only(self): + class A(fixtures.ComparableEntity): + pass + class B(fixtures.ComparableEntity): + pass + + mapper(A, self.tables.t1) + mapper(B, self.tables.t2, properties={ + 'a': relationship(A, viewonly=True) + }) + + a1 = A() + b1 = B() + b1.a = a1 + assert not inspect(b1).attrs.a.history.has_changes() + + self._assert_fk(a1, b1, False) + class ViewOnlyM2MBackrefTest(fixtures.MappedTest): @classmethod def define_tables(cls, metadata): @@ -1551,6 +1663,8 @@ class ViewOnlyM2MBackrefTest(fixtures.MappedTest): a1 = A() b1 = B(as_=[a1]) + assert not inspect(b1).attrs.as_.history.has_changes() + sess.add(a1) sess.flush() eq_( |
