对于sqlalchemy下的继承,我有些困惑,以至于我什至不确定在这里应该使用哪种继承类型(单表,联接表,具体)。我有一个基类,其中包含一些在子类之间共享的信息,以及一些完全独立的数据。有时,我需要所有类的数据,有时只需要子类的数据。这是一个例子:
class Building: def __init__(self, x, y): self.x = x self.y = y class Commercial(Building): def __init__(self, x, y, business): Building.__init__(self, x, y) self.business = business class Residential(Building): def __init__(self, x, y, numResidents): Building.__init__(self, x, y, layer) self.numResidents = numResidents
如何使用声明式将其转换为SQLAlchemy?那么,我将如何查询位于x>5和的建筑物y>3?或哪些居民楼只有一名居民?
x>5
y>3
选择如何表示继承主要是数据库设计的问题。为了提高性能,单表继承通常是最好的。从良好的数据库设计角度来看,联接表继承会更好。通过联接表继承,您可以拥有数据库强制实施的子类的外键,对子类字段具有非null约束要简单得多。具体表继承在两种情况下都是最糟糕的。
具有声明性的单表继承设置如下所示:
class Building(Base): __tablename__ = 'building' id = Column(Integer, primary_key=True) building_type = Column(String(32), nullable=False) x = Column(Float, nullable=False) y = Column(Float, nullable=False) __mapper_args__ = {'polymorphic_on': building_type} class Commercial(Building): __mapper_args__ = {'polymorphic_identity': 'commercial'} business = Column(String(50)) class Residential(Building): __mapper_args__ = {'polymorphic_identity': 'residential'} num_residents = Column(Integer)
要使其加入表继承,您需要添加
__tablename__ = 'commercial' id = Column(None, ForeignKey('building.id'), primary_key=True)
子类。
两种方法的查询基本相同:
# buildings that are within x>5 and y>3 session.query(Building).filter((Building.x > 5) & (Building.y > 3)) # Residential buildings that have only 1 resident session.query(Residential).filter(Residential.num_residents == 1)
要控制加载哪些字段,可以使用query.with_polymorphic()方法。
query.with_polymorphic()
使用继承进行数据映射时要考虑的最重要的事情是您实际上是需要继承还是可以进行聚合。如果您需要更改建筑物的类型,或者建筑物可以同时具有商业和居住方面,那么继承将是一个痛苦。在这些情况下,通常最好将商业和住宅方面作为相关对象。