【问题标题】:How to format a decimal and string as part of a hybrid expression?如何将小数和字符串格式化为混合表达式的一部分?
【发布时间】:2021-03-27 03:32:47
【问题描述】:

问题

我创建了一个混合属性,它由一个字符串和一个百分比格式的小数组成,但是在使用混合表达式时我得到了一个 TypeError。我已经尝试了 f 字符串的几种变体,包括首先将其转换为浮点数,但我仍然在同一行上得到错误。在混合属性表达式上执行此字符串格式化和连接的最佳方法是什么?

我想知道为什么“result_1”会出错,而“result_2”工作正常

型号

from decimal import Decimal as D
class SupplierDiscount(Base):
    __tablename__ = "tblSupplierDiscount"
    id = Column(Integer, primary_key=True)
    discount = Column(DECIMAL(5, 4), nullable=False)
    description = Column(String, nullable=False)
    
    
    @hybrid_property
    def disc_desc(self):
        return f'{self.description}: {self.discount * 100:.4f}%'


    @disc_desc.expression
    def disc_desc(cls):
        return f'{cls.description}: {cls.discount * 100:.4f}%' # Error generated here

result_1 - 首选方法 - 但会导致错误

result_1 = session.query(SupplierDiscount.id.label("SDId"),
                         SupplierDiscount.disc_desc.label("SDDDesc")
                         ).all()
print('Below is from result_1')
print(result_1)
for i in result_1:
    print(i.id, i.disc_desc)

结果_1 中产生错误

TypeError: unsupported format string passed to BinaryExpression.__format__

result_2 - 这可行,但这不是首选方法

result_2 = session.query(SupplierDiscount).all()
print('Below is from result_2')
print(result_2)
for i in result_2:
    print(i.id, i.disc_desc)

环境

SQLAlchemy==1.3.20
PostgreSQL 13

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    类级别和实例级别访问之间存在区别。混合属性用于实例级别,并使用 python 字符串格式来获得所需的结果。由于该表达式用于类级访问,因此需要将其定义为 SQL 表达式以返回所需的结果。参考docs

    知道了这一点,我们可以将代码重写为以下内容,以在类级别和实例级别实现相同的结果:

    from sqlalchemy import Column, Integer, create_engine, DECIMAL, String, func
    from sqlalchemy.engine import create_engine
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.ext.hybrid import hybrid_property
    from sqlalchemy.orm import Session
    
    Base = declarative_base()
    
    class Discount(Base):
        __tablename__ = 'Discount'
        id = Column(Integer, primary_key=True)
        description = Column(String)
        discount = Column(DECIMAL(5,4))
    
        @hybrid_property
        def disc_desc(self):
            return f'{self.description}: {self.discount * 100:.4f}%'
    
        @disc_desc.expression
        def disc_desc(cls):
            return cls.description + ' ' + func.cast(cls.discount * 100, String) + '%'
    
    
    engine = create_engine(dburl)
    
    Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)
    
    with Session(engine) as session:
        discount = Discount(description='test', discount=5.4)
    
        session.add(discount)
        session.commit()
    
        disc = session.query(Discount).first()
        print('Instance-level access')
        print(disc.disc_desc)
        print('')
    
        disc = session.query(Discount.disc_desc).first()
        print('Class-level access')
        print(disc.disc_desc)
    

    这会导致:

    Instance-level access
    test: 540.0000%
    
    Class-level access
    test: 540.0000%
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 1970-01-01
      • 2015-04-04
      • 2021-12-01
      • 1970-01-01
      • 2023-03-16
      相关资源
      最近更新 更多