summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2022-12-01 21:41:21 +0000
committerGerrit Code Review <gerrit@ci3.zzzcomputing.com>2022-12-01 21:41:21 +0000
commit123fffd7bf159d5b1c5a6a3e54f50945dc48ab2a (patch)
treee1560d41eb90b1d954ca46fe0c7bd44a3523d464 /doc
parent990663c732e5bde43ed05eba0ade6d96fc7a2b26 (diff)
parentde68627dd1ba9c2dd44bb3d11be1a3945b285205 (diff)
downloadsqlalchemy-123fffd7bf159d5b1c5a6a3e54f50945dc48ab2a.tar.gz
Merge "add new pattern for single inh column override" into main
Diffstat (limited to 'doc')
-rw-r--r--doc/build/changelog/unreleased_20/8822.rst19
-rw-r--r--doc/build/orm/inheritance.rst67
2 files changed, 50 insertions, 36 deletions
diff --git a/doc/build/changelog/unreleased_20/8822.rst b/doc/build/changelog/unreleased_20/8822.rst
new file mode 100644
index 000000000..c3f062ac9
--- /dev/null
+++ b/doc/build/changelog/unreleased_20/8822.rst
@@ -0,0 +1,19 @@
+.. change::
+ :tags: feature, orm
+ :tickets: 8822
+
+ Added a new parameter :paramref:`_orm.mapped_column.use_existing_column` to
+ accommodate the use case of a single-table inheritance mapping that uses
+ the pattern of more than one subclass indicating the same column to take
+ place on the superclass. This pattern was previously possible by using
+ :func:`_orm.declared_attr` in conjunction with locating the existing column
+ in the ``.__table__`` of the superclass, however is now updated to work
+ with :func:`_orm.mapped_column` as well as with pep-484 typing, in a
+ simple and succinct way.
+
+ .. seealso::
+
+ :ref:`orm_inheritance_column_conflicts`
+
+
+
diff --git a/doc/build/orm/inheritance.rst b/doc/build/orm/inheritance.rst
index 2552b6437..7d7213db7 100644
--- a/doc/build/orm/inheritance.rst
+++ b/doc/build/orm/inheritance.rst
@@ -325,8 +325,8 @@ their own.
.. _orm_inheritance_column_conflicts:
-Resolving Column Conflicts
-+++++++++++++++++++++++++++
+Resolving Column Conflicts with ``use_existing_column``
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Note in the previous section that the ``manager_name`` and ``engineer_info`` columns
are "moved up" to be applied to ``Employee.__table__``, as a result of their
@@ -366,18 +366,20 @@ will result in an error:
.. sourcecode:: text
- sqlalchemy.exc.ArgumentError: Column 'start_date' on class
- <class '__main__.Manager'> conflicts with existing
- column 'employee.start_date'
+
+ sqlalchemy.exc.ArgumentError: Column 'start_date' on class Manager conflicts
+ with existing column 'employee.start_date'. If using Declarative,
+ consider using the use_existing_column parameter of mapped_column() to
+ resolve conflicts.
The above scenario presents an ambiguity to the Declarative mapping system that
-may be resolved by using
-:class:`.declared_attr` to define the :class:`_schema.Column` conditionally,
-taking care to return the **existing column** via the parent ``__table__``
-if it already exists::
+may be resolved by using the :paramref:`_orm.mapped_column.use_existing_column`
+parameter on :func:`_orm.mapped_column`, which instructs :func:`_orm.mapped_column`
+to look on the inheriting superclass present and use the column that's already
+mapped, if already present, else to map a new column::
+
from sqlalchemy import DateTime
- from sqlalchemy.orm import declared_attr
class Employee(Base):
@@ -397,15 +399,7 @@ if it already exists::
"polymorphic_identity": "engineer",
}
- @declared_attr
- def start_date(cls) -> Mapped[datetime]:
- "Start date column, if not present already."
-
- # the DateTime type is required in the mapped_column
- # at the moment when used inside of a @declared_attr
- return Employee.__table__.c.get(
- "start_date", mapped_column(DateTime) # type: ignore
- )
+ start_date: Mapped[datetime] = mapped_column(use_existing_column=True)
class Manager(Employee):
@@ -413,20 +407,25 @@ if it already exists::
"polymorphic_identity": "manager",
}
- @declared_attr
- def start_date(cls) -> Mapped[datetime]:
- "Start date column, if not present already."
-
- # the DateTime type is required in the mapped_column
- # at the moment when used inside of a @declared_attr
- return Employee.__table__.c.get(
- "start_date", mapped_column(DateTime) # type: ignore
- )
+ start_date: Mapped[datetime] = mapped_column(use_existing_column=True)
Above, when ``Manager`` is mapped, the ``start_date`` column is
-already present on the ``Employee`` class; by returning the existing
-:class:`_schema.Column` object, the declarative system recognizes that this
-is the same column to be mapped to the two different subclasses separately.
+already present on the ``Employee`` class, having been provided by the
+``Engineer`` mapping already. The :paramref:`_orm.mapped_column.use_existing_column`
+parameter indicates to :func:`_orm.mapped_column` that it should look for the
+requested :class:`_schema.Column` on the mapped :class:`.Table` for
+``Employee`` first, and if present, maintain that existing mapping. If not
+present, :func:`_orm.mapped_column` will map the column normally, adding it
+as one of the columns in the :class:`.Table` referred towards by the
+``Employee`` superclass.
+
+
+.. versionadded:: 2.0.0b4 - Added :paramref:`_orm.mapped_column.use_existing_column`,
+ which provides a 2.0-compatible means of mapping a column on an inheriting
+ subclass conditionally. The previous approach which combines
+ :class:`.declared_attr` with a lookup on the parent ``.__table__``
+ continues to function as well, but lacks :pep:`484` typing support.
+
A similar concept can be used with mixin classes (see :ref:`orm_mixins_toplevel`)
to define a particular series of columns and/or other mapped attributes
@@ -445,11 +444,7 @@ from a reusable mixin class::
class HasStartDate:
- @declared_attr
- def start_date(cls) -> Mapped[datetime]:
- return cls.__table__.c.get(
- "start_date", mapped_column(DateTime) # type: ignore
- )
+ start_date: Mapped[datetime] = mapped_column(use_existing_column=True)
class Engineer(HasStartDate, Employee):