我有一个如下定义的声明表:
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。
答案 0 :(得分:1)
您正在寻找的构造称为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(...)
答案 1 :(得分:1)
您执行的任何查询都不会替换原始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)修复你的查询只有一个带有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