Столбец пользовательского запроса SQLAlchemy
-
20-09-2019 - |
Вопрос
У меня есть декларативная таблица, определенная следующим образом:
class Transaction(Base):
__tablename__ = "transactions"
id = Column(Integer, primary_key=True)
account_id = Column(Integer)
transfer_account_id = Column(Integer)
amount = Column(Numeric(12, 2))
...
Запрос должен быть:
SELECT id, (CASE WHEN transfer_account_id=1 THEN -amount ELSE amount) AS amount
FROM transactions
WHERE account_id = 1 OR transfer_account_id = 1
Мой код таков:
query = Transaction.query.filter_by(account_id=1, transfer_account_id=1)
query = query.add_column(case(...).label("amount"))
Но это не заменяет amount
колонна.
Пытаюсь сделать это с помощью в течение нескольких часов, и я не хочу использовать необработанный SQL.
Решение
Любой запрос, который вы сделаете, не заменит исходный amount
колонна.Но вы можете загрузить другой столбец, используя следующий запрос:
q = session.query(Transaction,
case([(Transaction.transfer_account_id==1, -1*Transaction.amount)], else_=Transaction.amount).label('special_amount')
)
q = q.filter(or_(Transaction.account_id==1, Transaction.transfer_account_id==1))
Это вернет не только Transaction
объекты, а скорее tuple(Transaction, Decimal)
Но если вы хотите, чтобы это свойство было частью вашего объекта, тогда:
С тех пор, как ваш case when ...
функция полностью независима от условия в WHERE
, Я бы посоветовал вам изменить свой код следующим образом:
1) добавьте свойство к вашему объекту, которое выполняет case when ...
проверьте следующим образом:
@property
def special_amount(self):
return -self.amount if self.transfer_account_id == 1 else self.amount
Вы можете полностью обернуть эту специальную обработку суммы, также предоставляя свойство setter:
@special_amount.setter
def special_amount(self, value):
if self.transfer_account_id is None:
raise Exception('Cannot decide on special handling, because transfer_account_id is not set')
self.amount = -value if self.transfer_account_id == 1 else value
2) исправьте ваш запрос, чтобы в нем было только предложение filter с or_
предложение (похоже, ваш запрос вообще не работает):
q = session.query(Transaction).filter(
or_(Transaction.account_id==1,
Transaction.transfer_account_id==1)
)
# then get your results with the proper amount sign:
for t in q.all():
print q.id, q.special_amount
Другие советы
Конструкция, которую вы ищете, называется column_property
.Вы могли бы использовать вторичный картограф, чтобы фактически заменить столбец суммы.Вы уверены, что не слишком усложняете себе задачу, не просто сохраняя отрицательные значения непосредственно в базе данных или присваивая "исправленному" столбцу другое имя?
from sqlalchemy.orm import mapper, column_property
wrongmapper = sqlalchemy.orm.mapper(Transaction, Transaction.__table,
non_primary = True,
properties = {'amount':
column_property(case([(Transaction.transfer_account_id==1, -1*Transaction.amount)],
else_=Transaction.amount)})
Session.query(wrongmapper).filter(...)