我很难用外键引用在SQLAlchemy中进行继承。
我有一个drives
表,它以id
作为主键:
Column | Type | Collation | Nullable | Default
---------------+-----------------------+-----------+----------+------------------------------------
id | integer | | not null | nextval('drives_id_seq'::regclass)
model | integer | | not null |
我还有另一个名为smart
的表,它看起来像这样,以<ts, drive>
作为主键,而drive
是引用drives.id
的外键:
Column | Type | Collation | Nullable | Default
---------------+-----------------------+-----------+----------+------------------------------------
drive | integer | | not null | nextval('drives_id_seq'::regclass)
ts | timestamp without timezone | | not null |
value | integer | | |
我具有以下表示上述表格的类定义。
class Drives(Base):
__tablename__ = 'drives'
id = Column('id', Integer, primary_key=True)
model = Column('model', String)
class Smart(Base):
___tablename__ = 'smart'
drive = Column('drive', Integer, ForeignKey=Drives.id)
ts = Column('ts', TIMESTAMP)
value = Column('value', Integer)
drives = relationship('Drives')
# I would like something like the following to work, but I get an AttributeError for `model`
__mapper_args__ = {'primary_key': [ts, drive], 'polymorphic_on': drives.model}
我想创建两个派生类ModelASmart
或ModelBSmart
,其中smart.value
根据与drive
对应的模型进行不同的解释。
class ModelASmart(Smart):
__mapper_args__ = {'polymorphic_identity': 'ModelA', 'primary_key': [Smart.ts, Smart.drive]}
@hybrid_property
def actual_value(self):
return self.value * 2
class ModelBSmart(Smart):
__mapper_args__ = {'polymorphic_identity': 'ModelB', 'primary_key': [Smart.ts, Smart.drive]}
@hybrid_property
def actual_value(self):
return self.value * 3
我的问题:如何将另一个表(model
)中的列(drives
)用作主表smart
中的鉴别符?
答案 0 :(得分:1)
您可以使用column_property
属性将model
设为Smart
的“本地”,但要花费一个相关的子查询:
class Drives(Base):
__tablename__ = 'drives'
id = Column(Integer, primary_key=True)
model = Column(String)
class Smart(Base):
__tablename__ = 'smart'
drive = Column(Integer, ForeignKey(Drives.id), primary_key=True)
ts = Column(DateTime, primary_key=True)
value = Column(Integer)
drives = relationship(Drives)
model = column_property(select([Drives.model]).where(Drives.id == drive))
__mapper_args__ = {'polymorphic_on': model}
class ModelASmart(Smart):
__mapper_args__ = {'polymorphic_identity': 'ModelA'}
@hybrid_property
def actual_value(self):
return self.value * 2
class ModelBSmart(Smart):
__mapper_args__ = {'polymorphic_identity': 'ModelB'}
@hybrid_property
def actual_value(self):
return self.value * 3
column属性将始终包含在查询中,这意味着相关的子查询将可能确定查询性能。
SQLAlchemy还具有其他通过关系引入属性的方法,例如association proxies和混合属性,但是不能用作polymorphic_on
鉴别符。还有另一种更具异国情调的可能性是在smart
和drives
表之间的map Smart
over a join。
另一种选择是放弃使用继承,而在Smart
上使用普通的混合属性:
class Drives(Base):
__tablename__ = 'drives'
id = Column(Integer, primary_key=True)
model = Column(String)
class Smart(Base):
__tablename__ = 'smart'
drive = Column(Integer, ForeignKey(Drives.id), primary_key=True)
ts = Column(DateTime, primary_key=True)
value = Column(Integer)
drives = relationship(Drives)
_model_coeff = {
'ModelA': 2,
'ModelB': 3,
}
@hybrid_property
def actual_value(self):
return self.value * self._model_coeff[self.drives.model]
@actual_value.expression
def actual_value(cls):
return cls.value * case(
cls._model_coeff,
value=select([Drives.model]).
where(Drives.id == cls.drive).
as_scalar())
这使用case()
中的"shorthand" format将查询dict
映射到SQL CASE
表达式。查询,例如:
session.query(Smart, Smart.actual_value)
将使用相关的子查询在系数之间进行选择,但还有一个使用紧急加载的选项:
session.query(Smart).options(joinedload(Smart.drives, innerjoin=True))
通过这种方式,相关的Drives
实例被加载到同一查询中,因此,在访问实例时,hybrid属性不需要执行获取操作:
# `s` is an instance from the previous eager loading query. This access
# will not fire additional queries.
s.actual_value