diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-02 18:51:49 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-02 18:51:49 -0500 |
commit | 8a7fdd4e5cf5e4d9ba71c66a06bcba6b1054cfef (patch) | |
tree | e4ce11d8516235d6df37ca91ea40bf31f8e6edc1 /lib/sqlalchemy/ext/declarative/base.py | |
parent | ca8fca63916897f1bbc2fa4f1ee440c6b5d9a88a (diff) | |
download | sqlalchemy-8a7fdd4e5cf5e4d9ba71c66a06bcba6b1054cfef.tar.gz |
- A quasi-regression where apparently in 0.8 you can set a class-level
attribute on declarative to simply refer directly to an :class:`.InstrumentedAttribute`
on a superclass or on the class itself, and it
acts more or less like a synonym; in 0.9, this fails to set up enough
bookkeeping to keep up with the more liberalized backref logic
from :ticket:`2789`. Even though this use case was never directly
considered, it is now detected by declarative at the "setattr()" level
as well as when setting up a subclass, and the mirrored/renamed attribute
is now set up as a :func:`.synonym` instead. [ticket:2900]
Diffstat (limited to 'lib/sqlalchemy/ext/declarative/base.py')
-rw-r--r-- | lib/sqlalchemy/ext/declarative/base.py | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py index f7668a540..69e4b9eea 100644 --- a/lib/sqlalchemy/ext/declarative/base.py +++ b/lib/sqlalchemy/ext/declarative/base.py @@ -6,9 +6,10 @@ """Internal implementation for declarative.""" from ...schema import Table, Column -from ...orm import mapper, class_mapper +from ...orm import mapper, class_mapper, synonym from ...orm.interfaces import MapperProperty from ...orm.properties import ColumnProperty, CompositeProperty +from ...orm.attributes import QueryableAttribute from ...orm.base import _is_mapped_class from ... import util, exc from ...sql import expression @@ -148,6 +149,15 @@ def _as_declarative(cls, classname, dict_): if isinstance(value, declarative_props): value = getattr(cls, k) + elif isinstance(value, QueryableAttribute) and \ + value.class_ is not cls and \ + value.key != k: + # detect a QueryableAttribute that's already mapped being + # assigned elsewhere in userland, turn into a synonym() + value = synonym(value.key) + setattr(cls, k, value) + + if (isinstance(value, tuple) and len(value) == 1 and isinstance(value[0], (Column, MapperProperty))): util.warn("Ignoring declarative-like tuple value of attribute " @@ -397,6 +407,7 @@ def _add_attribute(cls, key, value): adds it to the Mapper, adds a column to the mapped Table, etc. """ + if '__mapper__' in cls.__dict__: if isinstance(value, Column): _undefer_column_name(key, value) @@ -413,6 +424,14 @@ def _add_attribute(cls, key, value): key, clsregistry._deferred_relationship(cls, value) ) + elif isinstance(value, QueryableAttribute) and value.key != key: + # detect a QueryableAttribute that's already mapped being + # assigned elsewhere in userland, turn into a synonym() + value = synonym(value.key) + cls.__mapper__.add_property( + key, + clsregistry._deferred_relationship(cls, value) + ) else: type.__setattr__(cls, key, value) else: |