summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm/base.py')
-rw-r--r--lib/sqlalchemy/orm/base.py108
1 files changed, 107 insertions, 1 deletions
diff --git a/lib/sqlalchemy/orm/base.py b/lib/sqlalchemy/orm/base.py
index d3814abd5..20a683d8c 100644
--- a/lib/sqlalchemy/orm/base.py
+++ b/lib/sqlalchemy/orm/base.py
@@ -42,11 +42,13 @@ if typing.TYPE_CHECKING:
from ._typing import _ExternalEntityType
from ._typing import _InternalEntityType
from .attributes import InstrumentedAttribute
+ from .dynamic import AppenderQuery
from .instrumentation import ClassManager
from .interfaces import PropComparator
from .mapper import Mapper
from .state import InstanceState
from .util import AliasedClass
+ from .writeonly import WriteOnlyCollection
from ..sql._typing import _ColumnExpressionArgument
from ..sql._typing import _InfoType
from ..sql.elements import ColumnElement
@@ -726,7 +728,23 @@ class ORMDescriptor(Generic[_T], TypingOnly):
...
-class Mapped(ORMDescriptor[_T], roles.TypedColumnsClauseRole[_T], TypingOnly):
+class _MappedAnnotationBase(Generic[_T], TypingOnly):
+ """common class for Mapped and similar ORM container classes.
+
+ these are classes that can appear on the left side of an ORM declarative
+ mapping, containing a mapped class or in some cases a collection
+ surrounding a mapped class.
+
+ """
+
+ __slots__ = ()
+
+
+class Mapped(
+ ORMDescriptor[_T],
+ roles.TypedColumnsClauseRole[_T],
+ _MappedAnnotationBase[_T],
+):
"""Represent an ORM mapped attribute on a mapped class.
This class represents the complete descriptor interface for any class
@@ -811,3 +829,91 @@ class _DeclarativeMapped(Mapped[_T], _MappedAttribute[_T]):
"""
__slots__ = ()
+
+
+class DynamicMapped(_MappedAnnotationBase[_T]):
+ """Represent the ORM mapped attribute type for a "dynamic" relationship.
+
+ The :class:`_orm.DynamicMapped` type annotation may be used in an
+ :ref:`Annotated Declarative Table <orm_declarative_mapped_column>` mapping
+ to indicate that the ``lazy="dynamic"`` loader strategy should be used
+ for a particular :func:`_orm.relationship`.
+
+ .. legacy:: The "dynamic" lazy loader strategy is the legacy form of what
+ is now the "write_only" strategy described in the section
+ :ref:`write_only_relationship`.
+
+ E.g.::
+
+ class User(Base):
+ __tablename__ = "user"
+ id: Mapped[int] = mapped_column(primary_key=True)
+ addresses: DynamicMapped[Address] = relationship(
+ cascade="all,delete-orphan"
+ )
+
+ See the section :ref:`dynamic_relationship` for background.
+
+ .. versionadded:: 2.0
+
+ .. seealso::
+
+ :ref:`dynamic_relationship` - complete background
+
+ :class:`.WriteOnlyMapped` - fully 2.0 style version
+
+ """
+
+ __slots__ = ()
+
+ if TYPE_CHECKING:
+
+ def __get__(
+ self, instance: Optional[object], owner: Any
+ ) -> AppenderQuery[_T]:
+ ...
+
+ def __set__(self, instance: Any, value: typing.Collection[_T]) -> None:
+ ...
+
+
+class WriteOnlyMapped(_MappedAnnotationBase[_T]):
+ """Represent the ORM mapped attribute type for a "write only" relationship.
+
+ The :class:`_orm.WriteOnlyMapped` type annotation may be used in an
+ :ref:`Annotated Declarative Table <orm_declarative_mapped_column>` mapping
+ to indicate that the ``lazy="write_only"`` loader strategy should be used
+ for a particular :func:`_orm.relationship`.
+
+ E.g.::
+
+ class User(Base):
+ __tablename__ = "user"
+ id: Mapped[int] = mapped_column(primary_key=True)
+ addresses: WriteOnlyMapped[Address] = relationship(
+ cascade="all,delete-orphan"
+ )
+
+ See the section :ref:`write_only_relationship` for background.
+
+ .. versionadded:: 2.0
+
+ .. seealso::
+
+ :ref:`write_only_relationship` - complete background
+
+ :class:`.DynamicMapped` - includes legacy :class:`_orm.Query` support
+
+ """
+
+ __slots__ = ()
+
+ if TYPE_CHECKING:
+
+ def __get__(
+ self, instance: Optional[object], owner: Any
+ ) -> WriteOnlyCollection[_T]:
+ ...
+
+ def __set__(self, instance: Any, value: typing.Collection[_T]) -> None:
+ ...