我有一个分类帐表和一个相应的python类。 我使用SQLAlchemy定义了模型,如下所示,
struct RandomQuote {
let inspiration = [
"You are looking rather nice today, as always.",
"Hello gorgeous!",
"You rock, don't ever change!",
"Your hair is looking on fleek today!",
"That smile.",
"Somebody woke up on the right side of bed!"]
var lastQuote = 0
mutating func getRandomInspiration() -> String {
let max = inspiration.count - 1
// Swift 3
// var randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: max)
var randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(max)
if randomNumber == lastQuote {
randomNumber = max
}
lastQuote = randomNumber
return inspiration[randomNumber]
}
}
var rq = RandomQuote()
for _ in 1...10 {
print(rq.getRandomInspiration())
}
现在你可以看到,我想创建一个名为“amountInCAD”的混合属性。 Python级别的getter似乎工作正常。但是SQL表达式不起作用。
现在,如果我运行这样的查询:
class Ledger(Base):
__tablename__ = 'ledger'
currency_exchange_rate_lookup = {('CNY', 'CAD'): 0.2}
amount = Column(Numeric(10, 2), nullable=False)
currency = Column(String, nullable=False)
payment_method = Column(String)
notes = Column(UnicodeText)
@hybrid_property
def amountInCAD(self):
if self.currency == 'CAD':
return self.amount
exchange_rate = self.currency_exchange_rate_lookup[(self.currency, 'CAD')]
CAD_value = self.amount * Decimal(exchange_rate)
CAD_value = round(CAD_value, 2)
return CAD_value
@amountInCAD.expression
def amountInCAD(cls):
amount = cls.__table__.c.amount
currency_name = cls.__table__.c.currency
exchange_rate = cls.currency_exchange_rate_lookup[(currency_name, 'CAD')]
return case([
(cls.currency == 'CAD', amount),
], else_ = round((amount * Decimal(exchange_rate)),2))
SQLAlchemy给了我这个错误:
>>>db_session.query(Ledger).filter(Ledger.amountInCAD > 1000)
我研究了SQLAlchemy关于混合属性的在线文档。 http://docs.sqlalchemy.org/en/latest/orm/mapped_sql_expr.html#using-a-hybrid
将我的代码与示例代码进行比较,我不明白为什么我的代码不起作用。如果在官方示例中, File "ledger_db.py", line 43, in amountInCAD
exchange_rate = cls.currency_exchange_rate_lookup[(currency_name, 'CAD')]
KeyError: (Column('currency', String(), table=<ledger>, nullable=False), 'CAD')
可以引用一列有价值,为什么在我的代码中,cls.firstname
只返回cls.__table__.c.currency
而不是其值?
答案 0 :(得分:1)
cls.firstname
不是“引用价值”,而是Column
。 example中的cls.firstname + " " + cls.lastname
生成一个字符串连接SQL表达式,其行如下:
firstname || ' ' || lastname
这是混合属性神奇的一部分:它们使得编写可以在两个域中都起作用的简单表达式变得相对容易,但是在处理python实例和构建SQL表达式时仍然需要了解它们。
您可以稍微重新考虑自己的混合,并将转换选项实际传递到case
表达式中的数据库:
from sqlalchemy import func
...
@amountInCAD.expression
def amountInCAD(cls):
# This builds a list of (predicate, expression) tuples for case. The
# predicates compare each row's `currency` column against the bound
# `from_` currencies in SQL.
exchange_rates = [(cls.currency == from_,
# Note that this does not call python's round, but
# creates an SQL function expression. It also does not
# perform a multiplication, but produces an SQL expression
# `amount * :rate`. Not quite sure
# why you had the Decimal conversion, so kept it.
func.round(cls.amount * Decimal(rate), 2))
for (from_, to_), rate in
cls.currency_exchange_rate_lookup.items()
# Include only conversions to 'CAD'
if to_ == 'CAD']
return case(exchange_rates + [
# The default for 'CAD'
(cls.currency == 'CAD', cls.amount),
])
通过这种方式,您可以有效地将汇率查找作为CASE
表达式传递给SQL。