summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-11-19 19:16:26 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-11-19 19:16:26 -0500
commit63508b82cd5710c660383bcac5fcfd3bb6af83c1 (patch)
treed1d37de872d048d2beff170dac5324394ec58e99 /test
parent452ce0c2e7fae13a569341cbbe6f3a988c0c6360 (diff)
downloadsqlalchemy-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.py114
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_(