Чтобы исправить это на постоянной основе, измените / etc / passwd
От:
kwilson: x: 3042: 3042 :: / home / jjson: / bin / sh
Измените его на:
kwilson: x: 3042: 3042 :: / home / jjson: / bin / bash
Вы можете использовать атрибут 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
Свойство столбца всегда будет включено в ваши запросы, что означает, что коррелированный подзапрос, вероятно, будет определять производительность запроса.
В SQLAlchemy есть и другие способы введения атрибутов через отношения, такие как прокси-серверы ассоциации и гибридные свойства, но они не могут использоваться в качестве polymorphic_on
дискриминатора. Еще одной, немного более экзотической, возможностью будет отобразить Smart
поверх соединения между таблицами smart
и drives
.
Другой вариант - отказаться от использования наследования и использовать вместо него простое гибридное свойство в 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()
для сопоставления поиска dict
с выражением SQL CASE
. Запрос, такой как:
session.query(Smart, Smart.actual_value)
будет использовать коррелированный подзапрос для выбора между коэффициентами, но есть и другой вариант с использованием активной загрузки:
session.query(Smart).options(joinedload(Smart.drives, innerjoin=True))
Таким образом, связанный Drives
] экземпляр загружается в тот же запрос, поэтому гибридному свойству не нужно выполнять выборку при доступе к экземпляру:
# `s` is an instance from the previous eager loading query. This access
# will not fire additional queries.
s.actual_value