首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在SQLAlchemy中实现此混合属性的SQL级表达式?

如何在SQLAlchemy中实现此混合属性的SQL级表达式?
EN

Stack Overflow用户
提问于 2016-10-03 03:40:09
回答 1查看 861关注 0票数 0

我有一个分类账表和一个相应的python类。我使用SQLAlchemy定义了模型,如下所示

代码语言:javascript
复制
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))

现在,正如您所看到的,我希望创建一个名为"amountInCAD“的混合属性。Python级别的getter似乎运行良好。但是,SQL表达式不起作用。

现在,如果我运行这样的查询:

代码语言:javascript
复制
>>>db_session.query(Ledger).filter(Ledger.amountInCAD > 1000)

SQLAlchemy给出了这个错误:

代码语言:javascript
复制
  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')

我研究了SQLAlchemy关于混合属性的在线文档。Expr.html#使用-a-混合将我的代码与示例代码进行比较,我不明白为什么我的代码不能工作。如果在官方示例中,cls.firstname可以引用值列,为什么在我的代码中cls.__table__.c.currency只返回一个Column而不是它的值?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-10-03 21:34:39

cls.firstname不是“引用值”,而是Columncls.firstname + " " + cls.lastname示例中生成一个字符串连接SQL表达式,如下所示:

代码语言:javascript
复制
firstname || ' ' || lastname

这是混合属性的魔力之一:它们使编写可以在这两个域中工作的简单表达式相对容易,但在处理python实例和构建SQL表达式时仍然需要理解。

您可以重新考虑一下自己的混合操作,并将转换选项传递给case表达式中的DB:

代码语言:javascript
复制
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。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39824292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档