almost the same way as we do other forms of inheritance mappings::
from sqlalchemy.ext.declarative import ConcreteBase
+ from sqlalchemy.orm import declarative_base
+ Base = declarative_base()
class Employee(ConcreteBase, Base):
__tablename__ = "employee"
in order to accommodate for those columns that aren't members of that
particular subclass.
+.. seealso::
+
+ :class:`.ConcreteBase`
+
+.. _abstract_concrete_base:
+
Abstract Concrete Classes
+++++++++++++++++++++++++
When using Declarative, just declare the
base class with the ``__abstract__`` indicator::
+ from sqlalchemy.orm import declarative_base
+
+ Base = declarative_base()
+
class Employee(Base):
__abstract__ = True
name = Column(String(50))
manager_data = Column(String(40))
- __mapper_args__ = {
- "polymorphic_identity": "manager",
- }
-
class Engineer(Employee):
__tablename__ = "engineer"
name = Column(String(50))
engineer_info = Column(String(40))
- __mapper_args__ = {
- "polymorphic_identity": "engineer",
- }
-
Above, we are not actually making use of SQLAlchemy's inheritance mapping
facilities; we can load and persist instances of ``Manager`` and ``Engineer``
normally. The situation changes however when we need to **query polymorphically**,
class called :class:`.AbstractConcreteBase` which achieves this automatically::
from sqlalchemy.ext.declarative import AbstractConcreteBase
+ from sqlalchemy.orm import declarative_base
+
+ Base = declarative_base()
class Employee(AbstractConcreteBase, Base):
"concrete": True,
}
-The :class:`.AbstractConcreteBase` helper class has a more complex internal
-process than that of :class:`.ConcreteBase`, in that the entire mapping
+ Base.registry.configure()
+
+Above, the :meth:`_orm.registry.configure` method is invoked, which will
+trigger the ``Employee`` class to be actually mapped; before the configuration
+step, the class has no mapping as the sub-tables which it will query from
+have not yet been defined. This process is more complex than that of
+:class:`.ConcreteBase`, in that the entire mapping
of the base class must be delayed until all the subclasses have been declared.
With a mapping like the above, only instances of ``Manager`` and ``Engineer``
may be persisted; querying against the ``Employee`` class will always produce
``Manager`` and ``Engineer`` objects.
+.. seealso::
+
+ :class:`.AbstractConcreteBase`
+
Classical and Semi-Classical Concrete Polymorphic Configuration
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. note::
- The :class:`.AbstractConcreteBase` class does not intend to set up the
- mapping for the base class until all the subclasses have been defined,
+ The :class:`.AbstractConcreteBase` delays the mapper creation of the
+ base class until all the subclasses have been defined,
as it needs to create a mapping against a selectable that will include
all subclass tables. In order to achieve this, it waits for the
**mapper configuration event** to occur, at which point it scans
While this event is normally invoked automatically, in the case of
:class:`.AbstractConcreteBase`, it may be necessary to invoke it
explicitly after **all** subclass mappings are defined, if the first
- operation is to be a query against this base class. To do so, invoke
- :func:`.configure_mappers` once all the desired classes have been
- configured::
-
- from sqlalchemy.orm import configure_mappers
-
- configure_mappers()
-
- .. seealso::
-
- :func:`_orm.configure_mappers`
+ operation is to be a query against this base class. To do so, once all
+ the desired classes have been configured, the
+ :meth:`_orm.registry.configure` method on the :class:`_orm.registry`
+ in use can be invoked, which is available in relation to a particular
+ declarative base class::
+ Base.registry.configure()
Example::
from sqlalchemy.ext.declarative import AbstractConcreteBase
+ from sqlalchemy.orm import declarative_base
+
+ Base = declarative_base()
class Employee(AbstractConcreteBase, Base):
pass
__mapper_args__ = {
'polymorphic_identity':'manager',
- 'concrete':True}
+ 'concrete':True
+ }
- configure_mappers()
+ Base.registry.configure()
The abstract base class is handled by declarative in a special way;
at class configuration time, it behaves like a declarative mixin
__mapper_args__ = {
'polymorphic_identity':'manager',
- 'concrete':True}
+ 'concrete':True
+ }
- configure_mappers()
+ Base.registry.configure()
When we make use of our mappings however, both ``Manager`` and
``Employee`` will have an independently usable ``.company`` attribute::
- session.query(Employee).filter(Employee.company.has(id=5))
-
- .. versionchanged:: 1.0.0 - The mechanics of :class:`.AbstractConcreteBase`
- have been reworked to support relationships established directly
- on the abstract base, without any special configurational steps.
+ session.execute(
+ select(Employee).filter(Employee.company.has(id=5))
+ )
.. seealso::
:ref:`concrete_inheritance`
+ :ref:`abstract_concrete_base`
+
"""
__no_table__ = True