summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-11-30 15:30:24 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-11-30 15:30:24 -0500
commit2688fce67f9b0c99235887192f6371335f71dfd4 (patch)
tree6b708cefb7317378a11b5f48ca8f8f4ceedddb34
parent66773a8801a584d36b514e22a03d92d66fb2931b (diff)
downloadsqlalchemy-2688fce67f9b0c99235887192f6371335f71dfd4.tar.gz
- re-document synonyms and remove warnings about "superseded"; synonyms
are still useful, just include notes that for more complex descriptor operations, hybrids are probably preferable
-rw-r--r--doc/build/orm/mapper_config.rst86
-rw-r--r--lib/sqlalchemy/orm/descriptor_props.py83
2 files changed, 130 insertions, 39 deletions
diff --git a/doc/build/orm/mapper_config.rst b/doc/build/orm/mapper_config.rst
index 9cd9abaca..37d9a33e6 100644
--- a/doc/build/orm/mapper_config.rst
+++ b/doc/build/orm/mapper_config.rst
@@ -689,13 +689,13 @@ described at :class:`~.AttributeEvents`.
.. autofunction:: validates
-.. _synonyms:
+.. _mapper_hybrids:
Using Descriptors and Hybrids
-----------------------------
A more comprehensive way to produce modified behavior for an attribute is to
-use descriptors. These are commonly used in Python using the ``property()``
+use :term:`descriptors`. These are commonly used in Python using the ``property()``
function. The standard SQLAlchemy technique for descriptors is to create a
plain descriptor, and to have it read/write from a mapped attribute with a
different name. Below we illustrate this using Python 2.6-style properties::
@@ -819,14 +819,88 @@ attribute, a SQL function is rendered which produces the same effect:
Read more about Hybrids at :ref:`hybrids_toplevel`.
+.. _synonyms:
+
Synonyms
--------
-Synonyms are a mapper-level construct that applies expression behavior to a descriptor
-based attribute.
+Synonyms are a mapper-level construct that allow any attribute on a class
+to "mirror" another attribute that is mapped.
-.. versionchanged:: 0.7
- The functionality of synonym is superceded as of 0.7 by hybrid attributes.
+In the most basic sense, the synonym is an easy way to make a certain
+attribute available by an additional name::
+
+ class MyClass(Base):
+ __tablename__ = 'my_table'
+
+ id = Column(Integer, primary_key=True)
+ job_status = Column(String(50))
+
+ status = synonym("job_status")
+
+The above class ``MyClass`` has two attributes, ``.job_status`` and
+``.status`` that will behave as one attribute, both at the expression
+level::
+
+ >>> print MyClass.job_status == 'some_status'
+ my_table.job_status = :job_status_1
+
+ >>> print MyClass.status == 'some_status'
+ my_table.job_status = :job_status_1
+
+and at the instance level::
+
+ >>> m1 = MyClass(status='x')
+ >>> m1.status, m1.job_status
+ ('x', 'x')
+
+ >>> m1.job_status = 'y'
+ >>> m1.status, m1.job_status
+ ('y', 'y')
+
+The :func:`.synonym` can be used for any kind of mapped attribute that
+subclasses :class:`.MapperProperty`, including mapped columns and relationships,
+as well as synonyms themselves.
+
+Beyond a simple mirror, :func:`.synonym` can also be made to reference
+a user-defined :term:`descriptor`. We can supply our
+``status`` synonym with a ``@property``::
+
+ class MyClass(Base):
+ __tablename__ = 'my_table'
+
+ id = Column(Integer, primary_key=True)
+ status = Column(String(50))
+
+ @property
+ def job_status(self):
+ return "Status: " + self.status
+
+ job_status = synonym("status", descriptor=job_status)
+
+When using Declarative, the above pattern can be expressed more succinctly
+using the :func:`.synonym_for` decorator::
+
+ from sqlalchemy.ext.declarative import synonym_for
+
+ class MyClass(Base):
+ __tablename__ = 'my_table'
+
+ id = Column(Integer, primary_key=True)
+ status = Column(String(50))
+
+ @synonym_for("status")
+ @property
+ def job_status(self):
+ return "Status: " + self.status
+
+While the :func:`.synonym` is useful for simple mirroring, the use case
+of augmenting attribute behavior with descriptors is better handled in modern
+usage using the :ref:`hybrid attribute <mapper_hybrids>` feature, which
+is more oriented towards Python descriptors. Techically, a :func:`.synonym`
+can do everything that a :class:`.hybrid_property` can do, as it also supports
+injection of custom SQL capabilities, but the hybrid is more straightforward
+to use in more complex situations.
.. autofunction:: synonym
diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py
index daf125ea2..1156a140e 100644
--- a/lib/sqlalchemy/orm/descriptor_props.py
+++ b/lib/sqlalchemy/orm/descriptor_props.py
@@ -488,40 +488,57 @@ class SynonymProperty(DescriptorProperty):
def __init__(self, name, map_column=None,
descriptor=None, comparator_factory=None,
doc=None):
- """Denote an attribute name as a synonym to a mapped property.
+ """Denote an attribute name as a synonym to a mapped property,
+ in that the attribute will mirror the value and expression behavior
+ of another attribute.
- .. versionchanged:: 0.7
- :func:`.synonym` is superseded by the :mod:`~sqlalchemy.ext.hybrid`
- extension. See the documentation for hybrids
- at :ref:`hybrids_toplevel`.
-
- Used with the ``properties`` dictionary sent to
- :func:`~sqlalchemy.orm.mapper`::
-
- class MyClass(object):
- def _get_status(self):
- return self._status
- def _set_status(self, value):
- self._status = value
- status = property(_get_status, _set_status)
-
- mapper(MyClass, sometable, properties={
- "status":synonym("_status", map_column=True)
- })
-
- Above, the ``status`` attribute of MyClass will produce
- expression behavior against the table column named ``status``,
- using the Python attribute ``_status`` on the mapped class
- to represent the underlying value.
-
- :param name: the name of the existing mapped property, which can be
- any other ``MapperProperty`` including column-based properties and
- relationships.
-
- :param map_column: if ``True``, an additional ``ColumnProperty`` is created
- on the mapper automatically, using the synonym's name as the keyname of
- the property, and the keyname of this ``synonym()`` as the name of the
- column to map.
+ :param name: the name of the existing mapped property. This
+ can refer to the string name of any :class:`.MapperProperty`
+ configured on the class, including column-bound attributes
+ and relationships.
+
+ :param descriptor: a Python :term:`descriptor` that will be used
+ as a getter (and potentially a setter) when this attribute is
+ accessed at the instance level.
+
+ :param map_column: if ``True``, the :func:`.synonym` construct will
+ locate the existing named :class:`.MapperProperty` based on the
+ attribute name of this :func:`.synonym`, and assign it to a new
+ attribute linked to the name of this :func:`.synonym`.
+ That is, given a mapping like::
+
+ class MyClass(Base):
+ __tablename__ = 'my_table'
+
+ id = Column(Integer, primary_key=True)
+ job_status = Column(String(50))
+
+ job_status = synonym("_job_status", map_column=True)
+
+ The above class ``MyClass`` will now have the ``job_status``
+ :class:`.Column` object mapped to the attribute named ``_job_status``,
+ and the attribute named ``job_status`` will refer to the synonym
+ itself. This feature is typically used in conjunction with the
+ ``descriptor`` argument in order to link a user-defined descriptor
+ as a "wrapper" for an existing column.
+
+ :param comparator_factory: A subclass of :class:`.PropComparator`
+ that will provide custom comparison behavior at the SQL expression
+ level.
+
+ .. note::
+
+ For the use case of providing an attribute which redefines both
+ Python-level and SQL-expression level behavior of an attribute,
+ please refer to the Hybrid attribute introduced at
+ :ref:`mapper_hybrids` for a more effective technique.
+
+ .. seealso::
+
+ :ref:`synonyms` - examples of functionality.
+
+ :ref:`mapper_hybrids` - Hybrids provide a better approach for
+ more complicated attribute-wrapping schemes than synonyms.
"""