column as well as the identifier for the base class::
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'employee',
- 'polymorphic_on':type
+ "polymorphic_identity": "employee",
+ "polymorphic_on": type,
}
Above, an additional column ``type`` is established to act as the
columns), as well as a foreign key reference to the parent table::
class Engineer(Employee):
- __tablename__ = 'engineer'
- id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
+ __tablename__ = "engineer"
+ id = Column(Integer, ForeignKey("employee.id"), primary_key=True)
engineer_name = Column(String(30))
__mapper_args__ = {
- 'polymorphic_identity':'engineer',
+ "polymorphic_identity": "engineer",
}
+
class Manager(Employee):
- __tablename__ = 'manager'
- id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
+ __tablename__ = "manager"
+ id = Column(Integer, ForeignKey("employee.id"), primary_key=True)
manager_name = Column(String(30))
__mapper_args__ = {
- 'polymorphic_identity':'manager',
+ "polymorphic_identity": "manager",
}
In the above example, each mapping specifies the
and ``Employee``::
class Company(Base):
- __tablename__ = 'company'
+ __tablename__ = "company"
id = Column(Integer, primary_key=True)
name = Column(String(50))
employees = relationship("Employee", back_populates="company")
+
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
company = relationship("Company", back_populates="employees")
__mapper_args__ = {
- 'polymorphic_identity':'employee',
- 'polymorphic_on':type
+ "polymorphic_identity": "employee",
+ "polymorphic_on": type,
}
+
class Manager(Employee):
- # ...
+ ...
+
class Engineer(Employee):
- # ...
+ ...
If the foreign key constraint is on a table corresponding to a subclass,
the relationship should target that subclass instead. In the example
established between the ``Manager`` and ``Company`` classes::
class Company(Base):
- __tablename__ = 'company'
+ __tablename__ = "company"
id = Column(Integer, primary_key=True)
name = Column(String(50))
managers = relationship("Manager", back_populates="company")
+
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'employee',
- 'polymorphic_on':type
+ "polymorphic_identity": "employee",
+ "polymorphic_on": type,
}
+
class Manager(Employee):
- __tablename__ = 'manager'
- id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
+ __tablename__ = "manager"
+ id = Column(Integer, ForeignKey("employee.id"), primary_key=True)
manager_name = Column(String(30))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
company = relationship("Company", back_populates="managers")
__mapper_args__ = {
- 'polymorphic_identity':'manager',
+ "polymorphic_identity": "manager",
}
+
class Engineer(Employee):
- # ...
+ ...
Above, the ``Manager`` class will have a ``Manager.company`` attribute;
``Company`` will have a ``Company.managers`` attribute that always
the :class:`_schema.Column` will be applied to the same base :class:`_schema.Table` object::
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(20))
__mapper_args__ = {
- 'polymorphic_on':type,
- 'polymorphic_identity':'employee'
+ "polymorphic_on": type,
+ "polymorphic_identity": "employee",
}
+
class Manager(Employee):
manager_data = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'manager'
+ "polymorphic_identity": "manager",
}
+
class Engineer(Employee):
engineer_info = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'engineer'
+ "polymorphic_identity": "engineer",
}
Note that the mappers for the derived classes Manager and Engineer omit the
comes up when two subclasses want to specify *the same* column, as below::
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(20))
__mapper_args__ = {
- 'polymorphic_on':type,
- 'polymorphic_identity':'employee'
+ "polymorphic_on": type,
+ "polymorphic_identity": "employee",
}
+
class Engineer(Employee):
- __mapper_args__ = {'polymorphic_identity': 'engineer'}
+ __mapper_args__ = {
+ "polymorphic_identity": "engineer",
+ }
start_date = Column(DateTime)
+
class Manager(Employee):
- __mapper_args__ = {'polymorphic_identity': 'manager'}
+ __mapper_args__ = {
+ "polymorphic_identity": "manager",
+ }
start_date = Column(DateTime)
Above, the ``start_date`` column declared on both ``Engineer`` and ``Manager``
from sqlalchemy.orm import declared_attr
+
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(20))
__mapper_args__ = {
- 'polymorphic_on':type,
- 'polymorphic_identity':'employee'
+ "polymorphic_on": type,
+ "polymorphic_identity": "employee",
}
+
class Engineer(Employee):
- __mapper_args__ = {'polymorphic_identity': 'engineer'}
+ __mapper_args__ = {
+ "polymorphic_identity": "engineer",
+ }
@declared_attr
def start_date(cls):
"Start date column, if not present already."
- return Employee.__table__.c.get('start_date', Column(DateTime))
+ return Employee.__table__.c.get("start_date", Column(DateTime))
+
class Manager(Employee):
- __mapper_args__ = {'polymorphic_identity': 'manager'}
+ __mapper_args__ = {
+ "polymorphic_identity": "manager",
+ }
@declared_attr
def start_date(cls):
"Start date column, if not present already."
- return Employee.__table__.c.get('start_date', Column(DateTime))
+ return Employee.__table__.c.get("start_date", Column(DateTime))
Above, when ``Manager`` is mapped, the ``start_date`` column is
already present on the ``Employee`` class; by returning the existing
from a reusable mixin class::
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(20))
__mapper_args__ = {
- 'polymorphic_on':type,
- 'polymorphic_identity':'employee'
+ "polymorphic_on": type,
+ "polymorphic_identity": "employee",
}
+
class HasStartDate:
@declared_attr
def start_date(cls):
- return cls.__table__.c.get('start_date', Column(DateTime))
+ return cls.__table__.c.get("start_date", Column(DateTime))
+
class Engineer(HasStartDate, Employee):
- __mapper_args__ = {'polymorphic_identity': 'engineer'}
+ __mapper_args__ = {
+ "polymorphic_identity": "engineer",
+ }
+
class Manager(HasStartDate, Employee):
- __mapper_args__ = {'polymorphic_identity': 'manager'}
+ __mapper_args__ = {
+ "polymorphic_identity": "manager",
+ }
Relationships with Single Table Inheritance
+++++++++++++++++++++++++++++++++++++++++++
relationship::
class Company(Base):
- __tablename__ = 'company'
+ __tablename__ = "company"
id = Column(Integer, primary_key=True)
name = Column(String(50))
employees = relationship("Employee", back_populates="company")
+
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
company = relationship("Company", back_populates="employees")
__mapper_args__ = {
- 'polymorphic_identity':'employee',
- 'polymorphic_on':type
+ "polymorphic_identity": "employee",
+ "polymorphic_on": type,
}
manager_data = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'manager'
+ "polymorphic_identity": "manager",
}
+
class Engineer(Employee):
engineer_info = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'engineer'
+ "polymorphic_identity": "engineer",
}
Also, like the case of joined inheritance, we can create relationships
or subclasses::
class Company(Base):
- __tablename__ = 'company'
+ __tablename__ = "company"
id = Column(Integer, primary_key=True)
name = Column(String(50))
managers = relationship("Manager", back_populates="company")
+
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'employee',
- 'polymorphic_on':type
+ "polymorphic_identity": "employee",
+ "polymorphic_on": type,
}
class Manager(Employee):
manager_name = Column(String(30))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
company = relationship("Company", back_populates="managers")
__mapper_args__ = {
- 'polymorphic_identity':'manager',
+ "polymorphic_identity": "manager",
}
engineer_info = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity':'engineer'
+ "polymorphic_identity": "engineer",
}
Above, the ``Manager`` class will have a ``Manager.company`` attribute;
table should not be considered as part of the mapping::
class Employee(Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
+
class Manager(Employee):
- __tablename__ = 'manager'
+ __tablename__ = "manager"
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(50))
__mapper_args__ = {
- 'concrete': True
+ "concrete": True,
}
+
class Engineer(Employee):
- __tablename__ = 'engineer'
+ __tablename__ = "engineer"
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(50))
__mapper_args__ = {
- 'concrete': True
+ "concrete": True,
}
Two critical points should be noted:
from sqlalchemy.ext.declarative import ConcreteBase
+
class Employee(ConcreteBase, Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
__mapper_args__ = {
- 'polymorphic_identity': 'employee',
- 'concrete': True
+ "polymorphic_identity": "employee",
+ "concrete": True,
}
+
class Manager(Employee):
- __tablename__ = 'manager'
+ __tablename__ = "manager"
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
__mapper_args__ = {
- 'polymorphic_identity': 'manager',
- 'concrete': True
+ "polymorphic_identity": "manager",
+ "concrete": True,
}
+
class Engineer(Employee):
- __tablename__ = 'engineer'
+ __tablename__ = "engineer"
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
__mapper_args__ = {
- 'polymorphic_identity': 'engineer',
- 'concrete': True
+ "polymorphic_identity": "engineer",
+ "concrete": True,
}
Above, Declarative sets up the polymorphic selectable for the
class Employee(Base):
__abstract__ = True
+
class Manager(Employee):
- __tablename__ = 'manager'
+ __tablename__ = "manager"
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
__mapper_args__ = {
- 'polymorphic_identity': 'manager',
+ "polymorphic_identity": "manager",
}
+
class Engineer(Employee):
- __tablename__ = 'engineer'
+ __tablename__ = "engineer"
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
__mapper_args__ = {
- 'polymorphic_identity': 'engineer',
+ "polymorphic_identity": "engineer",
}
Above, we are not actually making use of SQLAlchemy's inheritance mapping
from sqlalchemy.ext.declarative import AbstractConcreteBase
+
class Employee(AbstractConcreteBase, Base):
pass
+
class Manager(Employee):
- __tablename__ = 'manager'
+ __tablename__ = "manager"
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
__mapper_args__ = {
- 'polymorphic_identity': 'manager',
- 'concrete': True
+ "polymorphic_identity": "manager",
+ "concrete": True,
}
+
class Engineer(Employee):
- __tablename__ = 'engineer'
+ __tablename__ = "engineer"
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
__mapper_args__ = {
- 'polymorphic_identity': 'engineer',
- 'concrete': True
+ "polymorphic_identity": "engineer",
+ "concrete": True,
}
The :class:`.AbstractConcreteBase` helper class has a more complex internal
metadata_obj = Base.metadata
employees_table = Table(
- 'employee', metadata_obj,
- Column('id', Integer, primary_key=True),
- Column('name', String(50)),
+ "employee",
+ metadata_obj,
+ Column("id", Integer, primary_key=True),
+ Column("name", String(50)),
)
managers_table = Table(
- 'manager', metadata_obj,
- Column('id', Integer, primary_key=True),
- Column('name', String(50)),
- Column('manager_data', String(50)),
+ "manager",
+ metadata_obj,
+ Column("id", Integer, primary_key=True),
+ Column("name", String(50)),
+ Column("manager_data", String(50)),
)
engineers_table = Table(
- 'engineer', metadata_obj,
- Column('id', Integer, primary_key=True),
- Column('name', String(50)),
- Column('engineer_info', String(50)),
+ "engineer",
+ metadata_obj,
+ Column("id", Integer, primary_key=True),
+ Column("name", String(50)),
+ Column("engineer_info", String(50)),
)
Next, the UNION is produced using :func:`.polymorphic_union`::
from sqlalchemy.orm import polymorphic_union
- pjoin = polymorphic_union({
- 'employee': employees_table,
- 'manager': managers_table,
- 'engineer': engineers_table
- }, 'type', 'pjoin')
+ pjoin = polymorphic_union(
+ {
+ "employee": employees_table,
+ "manager": managers_table,
+ "engineer": engineers_table,
+ },
+ "type",
+ "pjoin",
+ )
With the above :class:`_schema.Table` objects, the mappings can be produced using "semi-classical" style,
where we use Declarative in conjunction with the ``__table__`` argument;
class Employee(Base):
__table__ = employee_table
__mapper_args__ = {
- 'polymorphic_on': pjoin.c.type,
- 'with_polymorphic': ('*', pjoin),
- 'polymorphic_identity': 'employee'
+ "polymorphic_on": pjoin.c.type,
+ "with_polymorphic": ("*", pjoin),
+ "polymorphic_identity": "employee",
}
+
class Engineer(Employee):
__table__ = engineer_table
__mapper_args__ = {
- 'polymorphic_identity': 'engineer',
- 'concrete': True}
+ "polymorphic_identity": "engineer",
+ "concrete": True,
+ }
+
class Manager(Employee):
__table__ = manager_table
__mapper_args__ = {
- 'polymorphic_identity': 'manager',
- 'concrete': True}
+ "polymorphic_identity": "manager",
+ "concrete": True,
+ }
Alternatively, the same :class:`_schema.Table` objects can be used in
fully "classical" style, without using Declarative at all.
for k in kw:
setattr(self, k, kw[k])
+
class Manager(Employee):
pass
+
class Engineer(Employee):
pass
+
employee_mapper = mapper_registry.map_imperatively(
Employee,
pjoin,
- with_polymorphic=('*', pjoin),
+ with_polymorphic=("*", pjoin),
polymorphic_on=pjoin.c.type,
)
manager_mapper = mapper_registry.map_imperatively(
managers_table,
inherits=employee_mapper,
concrete=True,
- polymorphic_identity='manager',
+ polymorphic_identity="manager",
)
engineer_mapper = mapper_registry.map_imperatively(
Engineer,
engineers_table,
inherits=employee_mapper,
concrete=True,
- polymorphic_identity='engineer',
+ polymorphic_identity="engineer",
)
-
-
The "abstract" example can also be mapped using "semi-classical" or "classical"
style. The difference is that instead of applying the "polymorphic union"
to the :paramref:`.mapper.with_polymorphic` parameter, we apply it directly
from sqlalchemy.orm import polymorphic_union
- pjoin = polymorphic_union({
- 'manager': managers_table,
- 'engineer': engineers_table
- }, 'type', 'pjoin')
+ pjoin = polymorphic_union(
+ {
+ "manager": managers_table,
+ "engineer": engineers_table,
+ },
+ "type",
+ "pjoin",
+ )
+
class Employee(Base):
__table__ = pjoin
__mapper_args__ = {
- 'polymorphic_on': pjoin.c.type,
- 'with_polymorphic': '*',
- 'polymorphic_identity': 'employee'
+ "polymorphic_on": pjoin.c.type,
+ "with_polymorphic": "*",
+ "polymorphic_identity": "employee",
}
+
class Engineer(Employee):
__table__ = engineer_table
__mapper_args__ = {
- 'polymorphic_identity': 'engineer',
- 'concrete': True}
+ "polymorphic_identity": "engineer",
+ "concrete": True,
+ }
+
class Manager(Employee):
__table__ = manager_table
__mapper_args__ = {
- 'polymorphic_identity': 'manager',
- 'concrete': True}
+ "polymorphic_identity": "manager",
+ "concrete": True,
+ }
+
Above, we use :func:`.polymorphic_union` in the same manner as before, except
that we omit the ``employee`` table.
class Company(Base):
- __tablename__ = 'company'
+ __tablename__ = "company"
id = Column(Integer, primary_key=True)
name = Column(String(50))
employees = relationship("Employee")
class Employee(ConcreteBase, Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
__mapper_args__ = {
- 'polymorphic_identity': 'employee',
- 'concrete': True
+ "polymorphic_identity": "employee",
+ "concrete": True,
}
class Manager(Employee):
- __tablename__ = 'manager'
+ __tablename__ = "manager"
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
__mapper_args__ = {
- 'polymorphic_identity': 'manager',
- 'concrete': True
+ "polymorphic_identity": "manager",
+ "concrete": True,
}
class Engineer(Employee):
- __tablename__ = 'engineer'
+ __tablename__ = "engineer"
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
__mapper_args__ = {
- 'polymorphic_identity': 'engineer',
- 'concrete': True
+ "polymorphic_identity": "engineer",
+ "concrete": True,
}
The next complexity with concrete inheritance and relationships involves
class Company(Base):
- __tablename__ = 'company'
+ __tablename__ = "company"
id = Column(Integer, primary_key=True)
name = Column(String(50))
employees = relationship("Employee", back_populates="company")
class Employee(ConcreteBase, Base):
- __tablename__ = 'employee'
+ __tablename__ = "employee"
id = Column(Integer, primary_key=True)
name = Column(String(50))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
company = relationship("Company", back_populates="employees")
__mapper_args__ = {
- 'polymorphic_identity': 'employee',
- 'concrete': True
+ "polymorphic_identity": "employee",
+ "concrete": True,
}
class Manager(Employee):
- __tablename__ = 'manager'
+ __tablename__ = "manager"
id = Column(Integer, primary_key=True)
name = Column(String(50))
manager_data = Column(String(40))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
company = relationship("Company", back_populates="employees")
__mapper_args__ = {
- 'polymorphic_identity': 'manager',
- 'concrete': True
+ "polymorphic_identity": "manager",
+ "concrete": True,
}
class Engineer(Employee):
- __tablename__ = 'engineer'
+ __tablename__ = "engineer"
id = Column(Integer, primary_key=True)
name = Column(String(50))
engineer_info = Column(String(40))
- company_id = Column(ForeignKey('company.id'))
+ company_id = Column(ForeignKey("company.id"))
company = relationship("Company", back_populates="employees")
__mapper_args__ = {
- 'polymorphic_identity': 'engineer',
- 'concrete': True
+ "polymorphic_identity": "engineer",
+ "concrete": True,
}
The above limitation is related to the current implementation, including