声明式支持尽可能直观的所有三种形式的继承。inherits
mapper关键字参数不是必需的,因为声明将从类本身确定它。各种“多态”关键字参数使用__mapper_args__
指定。
也可以看看
Mapping Class Inheritance Hierarchies - 使用Declarative继承映射的一般介绍。
联合表继承被定义为定义其自己的表的子类:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__tablename__ = 'engineers'
__mapper_args__ = {'polymorphic_identity': 'engineer'}
id = Column(Integer, ForeignKey('people.id'), primary_key=True)
primary_language = Column(String(50))
Note that above, the Engineer.id
attribute, since it shares the same attribute name as the Person.id
attribute, will in fact represent the people.id
and engineers.id
columns together, with the “Engineer.id” column taking precedence if queried directly. 要为Engineer
类提供仅表示engineers.id
列的属性,请为其指定一个不同的属性名称:
class Engineer(Person):
__tablename__ = 'engineers'
__mapper_args__ = {'polymorphic_identity': 'engineer'}
engineer_id = Column('id', Integer, ForeignKey('people.id'),
primary_key=True)
primary_language = Column(String(50))
单表继承被定义为没有自己的表的子类;您只需省略__table__
和__tablename__
属性:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__mapper_args__ = {'polymorphic_identity': 'engineer'}
primary_language = Column(String(50))
当配置上述映射器时,在定义primary_language
列之前,将Person
类映射到people
表,而这一列将不会包含在它自己的映射中。当Engineer
然后定义primary_language
列时,该列将添加到people
表中,以便它包含在Engineer
也是表格全部列的一部分。未映射到Person
的列也使用exclude_properties
映射器参数从任何其他单个或已加入的继承类中排除。Below, Manager
will have all the attributes of Person
and Manager
but not the primary_language
attribute of Engineer
:
class Manager(Person):
__mapper_args__ = {'polymorphic_identity': 'manager'}
golf_swing = Column(String(50))
The attribute exclusion logic is provided by the exclude_properties
mapper argument, and declarative’s default behavior can be disabled by passing an explicit exclude_properties
collection (empty or otherwise) to the __mapper_args__
.
请注意,primary_language
和golf_swing
列被“向上移动”以应用于Person.__table__
,因为它们在没有自己的表的子类。当两个子类想要指定相同的列时出现一个棘手的情况,如下所示:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__mapper_args__ = {'polymorphic_identity': 'engineer'}
start_date = Column(DateTime)
class Manager(Person):
__mapper_args__ = {'polymorphic_identity': 'manager'}
start_date = Column(DateTime)
上面,在Engineer
和Manager
上声明的start_date
列将导致错误:
sqlalchemy.exc.ArgumentError: Column 'start_date' on class
<class '__main__.Manager'> conflicts with existing
column 'people.start_date'
在这种情况下,Declarative无法确定意图,特别是如果start_date
列包含不同的类型。A situation like this can be resolved by using declared_attr
to define the Column
conditionally, taking care to return the existing column via the parent __table__
if it already exists:
from sqlalchemy.ext.declarative import declared_attr
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class Engineer(Person):
__mapper_args__ = {'polymorphic_identity': 'engineer'}
@declared_attr
def start_date(cls):
"Start date column, if not present already."
return Person.__table__.c.get('start_date', Column(DateTime))
class Manager(Person):
__mapper_args__ = {'polymorphic_identity': 'manager'}
@declared_attr
def start_date(cls):
"Start date column, if not present already."
return Person.__table__.c.get('start_date', Column(DateTime))
在上面,当映射Manager
时,start_date
列已经存在于Person
类中。在这种情况下,Declarative让我们返回Column
,因为它知道跳过重新分配同一列。If the mapping is mis-configured such that the start_date
column is accidentally re-assigned to a different table (such as, if we changed Manager
to be joined inheritance without fixing start_date
), an error is raised which indicates an existing Column
is trying to be re-assigned to a different owning Table
.
0.8版中的新功能 declared_attr
可用于非mixin类,并且返回的Column
或其他映射属性将应用于映射为其他任何属性。以前,结果属性将被忽略,并且还会在创建子类时导致发出警告。
New in version 0.8: declared_attr
, when used either with a mixin or non-mixin declarative class, can return an existing Column
already assigned to the parent Table
, to indicate that the re-assignment of the Column
should be skipped, however should still be mapped on the target class, in order to resolve duplicate column conflicts.
mixin类可以使用相同的概念(请参阅Mixin and Custom Base Classes):
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
discriminator = Column('type', String(50))
__mapper_args__ = {'polymorphic_on': discriminator}
class HasStartDate(object):
@declared_attr
def start_date(cls):
return cls.__table__.c.get('start_date', Column(DateTime))
class Engineer(HasStartDate, Person):
__mapper_args__ = {'polymorphic_identity': 'engineer'}
class Manager(HasStartDate, Person):
__mapper_args__ = {'polymorphic_identity': 'manager'}
上面的mixin检查列的本地__table__
属性。因为我们使用单表继承,所以我们确信在这种情况下,cls.__table__
指的是Person.__table__
。如果我们混合了连接表和单表继承,那么我们可能希望我们的mixin更仔细地检查是否我们正在查找cls.__table__
真的是Table
。
混凝土定义为具有自己的表的子类,并将concrete
关键字参数设置为True
:
class Person(Base):
__tablename__ = 'people'
id = Column(Integer, primary_key=True)
name = Column(String(50))
class Engineer(Person):
__tablename__ = 'engineers'
__mapper_args__ = {'concrete':True}
id = Column(Integer, primary_key=True)
primary_language = Column(String(50))
name = Column(String(50))
抽象基类的使用不那么简单,因为它需要使用polymorphic_union()
,它需要在构建类之前使用Table
对象创建:
engineers = Table('engineers', Base.metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50)),
Column('primary_language', String(50))
)
managers = Table('managers', Base.metadata,
Column('id', Integer, primary_key=True),
Column('name', String(50)),
Column('golf_swing', String(50))
)
punion = polymorphic_union({
'engineer':engineers,
'manager':managers
}, 'type', 'punion')
class Person(Base):
__table__ = punion
__mapper_args__ = {'polymorphic_on':punion.c.type}
class Engineer(Person):
__table__ = engineers
__mapper_args__ = {'polymorphic_identity':'engineer', 'concrete':True}
class Manager(Person):
__table__ = managers
__mapper_args__ = {'polymorphic_identity':'manager', 'concrete':True}
帮助类AbstractConcreteBase
和ConcreteBase
为上述创建多态联合的系统提供了自动化。有关详细信息,请参阅这些助手的文档以及有关具体继承的主要ORM文档。