summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2020-03-03 08:58:35 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2020-03-03 08:58:35 -0500
commit4c81d99bab0e884473abfcb573772aa5d94264c7 (patch)
tree5d7e794e19b10dc8f0d432554a8f224200928a3c
parentb5050beb73b2e50b122c36e7dcdc06abffd472f2 (diff)
downloadsqlalchemy-4c81d99bab0e884473abfcb573772aa5d94264c7.tar.gz
Include column_property composition examples
Add cross-linking between column_property() and ColumnProperty Add section to describe using .expression remove inherited-members from ColumnProperty to greatly decrease verbosity Fixes: #5179 Change-Id: Ic477b16350dbf551100b31d14ff3ba8ba8221a43
-rw-r--r--doc/build/orm/internals.rst1
-rw-r--r--doc/build/orm/mapped_sql_expr.rst63
-rw-r--r--doc/build/orm/mapping_columns.rst1
-rw-r--r--lib/sqlalchemy/orm/properties.py28
4 files changed, 80 insertions, 13 deletions
diff --git a/doc/build/orm/internals.rst b/doc/build/orm/internals.rst
index a8d2d6aaf..2658e24ee 100644
--- a/doc/build/orm/internals.rst
+++ b/doc/build/orm/internals.rst
@@ -20,7 +20,6 @@ sections, are listed here.
.. autoclass:: sqlalchemy.orm.properties.ColumnProperty
:members:
- :inherited-members:
.. autoclass:: sqlalchemy.orm.properties.ComparableProperty
:members:
diff --git a/doc/build/orm/mapped_sql_expr.rst b/doc/build/orm/mapped_sql_expr.rst
index 425a4ece8..e04abba80 100644
--- a/doc/build/orm/mapped_sql_expr.rst
+++ b/doc/build/orm/mapped_sql_expr.rst
@@ -158,20 +158,61 @@ to add an additional property after the fact::
where(Address.user_id==User.id)
)
-For many-to-many relationships, use :func:`.and_` to join the fields of the
-association table to both tables in a relation, illustrated
-here with a classical mapping::
+For a :func:`.column_property` that refers to columns linked from a
+many-to-many relationship, use :func:`.and_` to join the fields of the
+association table to both tables in a relationship::
from sqlalchemy import and_
- mapper(Author, authors, properties={
- 'book_count': column_property(
- select([func.count(books.c.id)],
- and_(
- book_authors.c.author_id==authors.c.id,
- book_authors.c.book_id==books.c.id
- )))
- })
+ class Author(Base):
+ # ...
+
+ book_count = column_property(
+ select(
+ [func.count(books.c.id)]
+ ).where(
+ and_(
+ book_authors.c.author_id==authors.c.id,
+ book_authors.c.book_id==books.c.id
+ )
+ )
+ )
+
+.. _mapper_column_property_sql_expressions_composed:
+
+Composing from Column Properties at Mapping Time
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+It is possible to create mappings that combine multiple
+:class:`.ColumnProperty` objects together. The :class:`.ColumnProperty` will
+be interpreted as a SQL expression when used in a Core expression context,
+provided that it is targeted by an existing expression object; this works by
+the Core detecting that the object has a ``__clause_element__()`` method which
+returns a SQL expression. However, if the :class:`.ColumnProperty` is used as
+a lead object in an expression where there is no other Core SQL expression
+object to target it, the :attr:`.ColumnProperty.expression` attribute will
+return the underlying SQL expression so that it can be used to build SQL
+expressions consistently. Below, the ``File`` class contains an attribute
+``File.path`` that concatenates a string token to the ``File.filename``
+attribute, which is itself a :class:`.ColumnProperty`::
+
+
+ class File(Base):
+ __tablename__ = 'file'
+
+ id = Column(Integer, primary_key=True)
+ name = Column(String(64))
+ extension = Column(String(8))
+ filename = column_property(name + '.' + extension)
+ path = column_property('C:/' + filename.expression)
+
+When the ``File`` class is used in expressions normally, the attributes
+assigned to ``filename`` and ``path`` are usable directly. The use of the
+:attr:`.ColumnProperty.expression` attribute is only necessary when using
+the :class:`.ColumnProperty` directly within the mapping definition::
+
+ q = session.query(File.path).filter(File.filename == 'foo.txt')
+
Using a plain descriptor
------------------------
diff --git a/doc/build/orm/mapping_columns.rst b/doc/build/orm/mapping_columns.rst
index e07692388..7d7b69140 100644
--- a/doc/build/orm/mapping_columns.rst
+++ b/doc/build/orm/mapping_columns.rst
@@ -103,6 +103,7 @@ This approach is uncommon in modern usage. For dealing with reflected
tables, a more flexible approach is to use that described in
:ref:`mapper_automated_reflection_schemes`.
+.. _column_property_options:
Using column_property for column level options
----------------------------------------------
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py
index 7eabce80b..6ad8606e3 100644
--- a/lib/sqlalchemy/orm/properties.py
+++ b/lib/sqlalchemy/orm/properties.py
@@ -58,7 +58,7 @@ class ColumnProperty(StrategizedProperty):
)
def __init__(self, *columns, **kwargs):
- r"""Provide a column-level property for use with a Mapper.
+ r"""Provide a column-level property for use with a mapping.
Column-based properties can normally be applied to the mapper's
``properties`` dictionary using the :class:`.Column` element directly.
@@ -66,6 +66,9 @@ class ColumnProperty(StrategizedProperty):
the mapper's selectable; examples include SQL expressions, functions,
and scalar SELECT queries.
+ The :func:`.orm.column_property` function returns an instance of
+ :class:`.ColumnProperty`.
+
Columns that aren't present in the mapper's selectable won't be
persisted by the mapper and are effectively "read-only" attributes.
@@ -128,6 +131,14 @@ class ColumnProperty(StrategizedProperty):
:ref:`deferred_raiseload`
+ .. seealso::
+
+ :ref:`column_property_options` - to map columns while including
+ mapping options
+
+ :ref:`mapper_column_property_sql_expressions` - to map SQL
+ expressions
+
"""
super(ColumnProperty, self).__init__()
self._orig_columns = [
@@ -206,6 +217,21 @@ class ColumnProperty(StrategizedProperty):
def expression(self):
"""Return the primary column or expression for this ColumnProperty.
+ E.g.::
+
+
+ class File(Base):
+ # ...
+
+ name = Column(String(64))
+ extension = Column(String(8))
+ filename = column_property(name + '.' + extension)
+ path = column_property('C:/' + filename.expression)
+
+ .. seealso::
+
+ :ref:`mapper_column_property_sql_expressions_composed`
+
"""
return self.columns[0]