attribute, provided the name is the same as that
of the entity mapped column.
+ - Added new flag expire_on_flush=False to column_property(),
+ marks those properties that would otherwise be considered
+ to be "readonly", i.e. derived from SQL expressions,
+ to retain their value after a flush has occurred, including
+ if the parent object itself was involved in an update.
+
- Enhanced the instrumentation in the ORM to support
Py3K's new argument style of "required kw arguments",
i.e. fn(a, b, *, c, d), fn(a, b, *args, c, d).
:param doc:
optional string that will be applied as the doc on the
class-bound descriptor.
+
+ :param expire_on_flush=True:
+ Disable expiry on flush. A column_property() which refers
+ to a SQL expression (and not a single table-bound column)
+ is considered to be a "read only" property; populating it
+ has no effect on the state of data, and it can only return
+ database state. For this reason a column_property()'s value
+ is expired whenever the parent object is involved in a
+ flush, that is, has any kind of "dirty" state within a flush.
+ Setting this parameter to ``False`` will have the effect of
+ leaving any existing value present after the flush proceeds.
+ Note however that the :class:`.Session` with default expiration
+ settings still expires
+ all attributes after a :meth:`.Session.commit` call, however.
+ New in 0.7.3.
+
:param extension:
an
if mapper._readonly_props:
readonly = state.unmodified_intersection(
- [p.key for p in mapper._readonly_props]
+ [p.key for p in mapper._readonly_props
+ if p.expire_on_flush or p.key not in state.dict]
)
if readonly:
state.expire_attributes(state.dict, readonly)
:param descriptor:
+ :param expire_on_flush:
+
:param extension:
"""
self.descriptor = kwargs.pop('descriptor', None)
self.extension = kwargs.pop('extension', None)
self.active_history = kwargs.pop('active_history', False)
+ self.expire_on_flush = kwargs.pop('expire_on_flush', True)
if 'doc' in kwargs:
self.doc = kwargs.pop('doc')
mapper(Data, data, properties={
'aplusb':column_property(data.c.a + literal_column("' '") + data.c.b)
})
- self._test()
+ self._test(True)
+
+ def test_no_refresh(self):
+ Data, data = self.classes.Data, self.tables.data
+
+ mapper(Data, data, properties={
+ 'aplusb':column_property(data.c.a + literal_column("' '") + data.c.b,
+ expire_on_flush=False)
+ })
+ self._test(False)
def test_refreshes_post_init(self):
Data, data = self.classes.Data, self.tables.data
m = mapper(Data, data)
m.add_property('aplusb', column_property(data.c.a + literal_column("' '") + data.c.b))
- self._test()
+ self._test(True)
def test_with_inheritance(self):
subdata, data, Data = (self.tables.subdata,
sess.flush()
eq_(sd1.aplusb, "hello there")
- def _test(self):
+ def _test(self, expect_expiry):
Data = self.classes.Data
sess = create_session()
d1.b = "bye"
sess.flush()
- eq_(d1.aplusb, "hello bye")
+ if expect_expiry:
+ eq_(d1.aplusb, "hello bye")
+ else:
+ eq_(d1.aplusb, "hello there")
+
d1.b = 'foobar'
d1.aplusb = 'im setting this explicitly'