SQLalchemy - модель из запроса - PullRequest
       6

SQLalchemy - модель из запроса

5 голосов
/ 08 апреля 2020

У нас есть приложение, которое использует sqlalchemy в качестве ORM. Помимо таблиц сопоставления мы также используем его для сопоставления существующих представлений базы данных, что прекрасно работает.

Однако мы не можем найти простой способ сопоставления пользовательских запросов с моделями. Например, допустим, у нас есть отчет вроде:

q = session.query(
    Table1.field1, Table2.field2, func.sum(Table2.field3).label('sum')
).join(
    Table2, Table1.id == Table2.id
).filter(
    Table1.field1 == param1, Table1.field2 == param2
).group_by(
    Table1.field1, Table2.field2
) 

Мы хотели бы сопоставить этот запрос с классом вроде

class Report(CustomBaseModel):

    field1 = Column(Integer, primary_key=True)
    field2 = Column(Integer, primary_key=True)
    sum = Column(Numeric)

Наш CustomBaseModel уже имеет множество функций реализовано, поэтому возможность использовать его здесь приведет к меньшему дублированию кода. Например, использование декларативной базы таким образом позволило бы определить relationship s с другими таблицами.

Конечно, этот пример не работает, поскольку в базе данных нет выбираемого "report".

Я попытался установить __table__ = q.subquery() в классе Report. Таким образом, запрос работает, но невозможно определить столбцы, отношения или другие свойства. Возможно, есть лучший способ добиться этого.

1 Ответ

0 голосов
/ 17 апреля 2020

Я не совсем понимаю, какого поведения вы хотите добиться, в этом примере таблица Report существует, но не нужна, это просто иметь некоторые данные для запроса в упрощенном виде, my_query() и my_query_session() использовать обертку, которая обрабатывает ее как column в идее, что вы вызываете имя функции в запросе и она выводит результат.

@hybrid_property не может не принять *args ни **kwargs, ни @hybrid_method не будут.

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
from sqlalchemy.orm import sessionmaker
import sqlalchemy as sql

Base = declarative_base()
db_uri = 'sqlite:///test.db'
engine = sql.create_engine(db_uri)
Session = sessionmaker(bind=engine)
session = Session()

class Report(Base):
    __tablename__ = 'report'
    id = sql.Column(sql.Integer, primary_key=True)
    name = sql.Column(sql.String(30), default='Unknown')

    @hybrid_property
    def my_query(self):
        return self.name

    @hybrid_method
    def my_query_session(self, _session):
        return _session.query(Report).order_by(
            Report.id.desc()).first().name


if __name__ == '__main__':
    Report.__table__.create(engine)
    session.add(Report(name='Alex'))
    session.add(Report(name='Nata'))
    session.commit()

    query_data = session.query(Report).first()
    print(query_data.my_query)
    print(query_data.my_query_session(session))

...