diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-06-30 11:09:37 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-06-30 11:09:37 -0400 |
| commit | 3b24ccaf28fd85a6e54aa813fde8b3677253f67f (patch) | |
| tree | 0edd54a7c1a92f95c09415b6f524ccc719a4a7c4 /lib | |
| parent | 278c243aa35103f07a928222a2b07092796e2099 (diff) | |
| download | sqlalchemy-3b24ccaf28fd85a6e54aa813fde8b3677253f67f.tar.gz | |
A warning is emitted when trying to flush an object of an inherited
mapped class where the polymorphic discriminator has been assigned
to a value that is invalid for the class. [ticket:2750]
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 33 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/persistence.py | 3 |
2 files changed, 35 insertions, 1 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 7f14d83cb..12d2234d2 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -28,7 +28,7 @@ from .interfaces import MapperProperty, _InspectionAttr, _MappedAttribute from .util import _INSTRUMENTOR, _class_to_mapper, \ _state_mapper, class_mapper, \ - PathRegistry + PathRegistry, state_str import sys properties = util.importlater("sqlalchemy.orm", "properties") descriptor_props = util.importlater("sqlalchemy.orm", "descriptor_props") @@ -1040,6 +1040,8 @@ class Mapper(_InspectionAttr): if self.polymorphic_on is not None: self._set_polymorphic_identity = \ mapper._set_polymorphic_identity + self._validate_polymorphic_identity = \ + mapper._validate_polymorphic_identity else: self._set_polymorphic_identity = None return @@ -1050,10 +1052,39 @@ class Mapper(_InspectionAttr): state.get_impl(polymorphic_key).set(state, dict_, state.manager.mapper.polymorphic_identity, None) + def _validate_polymorphic_identity(mapper, state, dict_): + if dict_[polymorphic_key] not in \ + mapper._acceptable_polymorphic_identities: + util.warn( + "Flushing object %s with " + "incompatible polymorphic identity %r; the " + "object may not refresh and/or load correctly" % ( + state_str(state), + dict_[polymorphic_key] + ) + ) + self._set_polymorphic_identity = _set_polymorphic_identity + self._validate_polymorphic_identity = _validate_polymorphic_identity else: self._set_polymorphic_identity = None + + _validate_polymorphic_identity = None + + @_memoized_configured_property + def _acceptable_polymorphic_identities(self): + identities = set() + + stack = deque([self]) + while stack: + item = stack.popleft() + if item.mapped_table is self.mapped_table: + identities.add(item.polymorphic_identity) + stack.extend(item._inheriting_mappers) + + return identities + def _adapt_inherited_property(self, key, prop, init): if not self.concrete: self._configure_property(key, prop, init=False, setparent=False) diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py index a773786c4..944623b07 100644 --- a/lib/sqlalchemy/orm/persistence.py +++ b/lib/sqlalchemy/orm/persistence.py @@ -150,6 +150,9 @@ def _organize_states_for_save(base_mapper, states, uowtransaction): else: mapper.dispatch.before_update(mapper, connection, state) + if mapper._validate_polymorphic_identity: + mapper._validate_polymorphic_identity(mapper, state, dict_) + # detect if we have a "pending" instance (i.e. has # no instance_key attached to it), and another instance # with the same identity key already exists as persistent. |
