Иностранные ключи и наследование в SQLAlchemy

Чтобы исправить это на постоянной основе, измените / etc / passwd

От:

kwilson: x: 3042: 3042 :: / home / jjson: / bin / sh

Измените его на:

kwilson: x: 3042: 3042 :: / home / jjson: / bin / bash

1
задан Ilja Everilä 28 February 2019 в 09:40
поделиться

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

Свойство столбца всегда будет включено в ваши запросы, что означает, что коррелированный подзапрос, вероятно, будет определять производительность запроса.

В 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
0
ответ дан Ilja Everilä 28 February 2019 в 09:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: