sqlalchemy:hybrid_property的布尔表达式

时间:2019-02-28 11:44:41

标签: python sqlalchemy

我有一个sqlalchemy类,该类代表具有列FileIDSettlementDate的表。我想创建一个混合属性,以说明给定实例是否为其FileID的最大值SettlementDate,以及要在查询时使用的关联表达式。我已经成功地使该属性正常工作,但是在表达上却有些挣扎。这是现有的模型:


class Hdr(model.Base):

    id = Column('ID', Integer, primary_key=True)
    file_id = Column('FileID', BIGINT, ForeignKey('FileRegister.Files.ID'))
    settlement_date = Column('SettlementDate', Date)

    @hybrid_property
    def is_latest(self):
        subquery = (
            object_session(self)
            .query(func.max(Hdr.file_id).label('file_id'))
            .group_by(Hdr.settlement_date)
            .subquery()
        )

        return (
            object_session(self)
            .query(func.count(Hdr.file_id).cast(Boolean))
            .filter(subquery.c.file_id==self.file_id)
            .scalar()
        )

我想我可以按照以下方式做点事情:

subquery = (
    select((func.max(Hdr.file_id).label('file_id'), ))
    .group_by(Hdr.settlement_date)
    .alias('a')
)

s = select(
    case(
        whens=[
            (Hdr.file_id.in_(subquery), 1)
        ],
        else_=0
    )
)

但这会引发错误Boolean value of this clause is not defined

任何帮助将不胜感激!

跟踪如下:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
c:\Users\\venvs\insight\lib\site-packages\sqlalchemy-1.3.0b3-py3.7-win-amd64.egg\sqlalchemy\sql\selectable.py in __init__(self, columns, whereclause, from_obj, distinct, having, correlate, prefixes, suffixes, **kwargs)
   2889         try:
-> 2890             cols_present = bool(columns)
   2891         except TypeError:

c:\Users\\venvs\insight\lib\site-packages\sqlalchemy-1.3.0b3-py3.7-win-amd64.egg\sqlalchemy\sql\elements.py in __bool__(self)
    515     def __bool__(self):
--> 516         raise TypeError("Boolean value of this clause is not defined")
    517 

TypeError: Boolean value of this clause is not defined

During handling of the above exception, another exception occurred:

ArgumentError                             Traceback (most recent call last)
<ipython-input-20-4946a4bf7faa> in <module>
     10             (Hdr.file_id.in_(subquery), 1)
     11         ],
---> 12         else_=0
     13     )
     14 )

<string> in select(columns, whereclause, from_obj, distinct, having, correlate, prefixes, suffixes, **kwargs)

<string> in __init__(self, columns, whereclause, from_obj, distinct, having, correlate, prefixes, suffixes, **kwargs)

c:\Users\\venvs\insight\lib\site-packages\sqlalchemy-1.3.0b3-py3.7-win-amd64.egg\sqlalchemy\util\deprecations.py in warned(fn, *args, **kwargs)
    128                     )
    129 
--> 130             return fn(*args, **kwargs)
    131 
    132         doc = fn.__doc__ is not None and fn.__doc__ or ""

c:\Users\\venvs\insight\lib\site-packages\sqlalchemy-1.3.0b3-py3.7-win-amd64.egg\sqlalchemy\sql\selectable.py in __init__(self, columns, whereclause, from_obj, distinct, having, correlate, prefixes, suffixes, **kwargs)
   2891         except TypeError:
   2892             raise exc.ArgumentError(
-> 2893                 "columns argument to select() must "
   2894                 "be a Python list or other iterable"
   2895             )

ArgumentError: columns argument to select() must be a Python list or other iterable

1 个答案:

答案 0 :(得分:1)

问题是

s = select(case(...))

select()的第一个参数应该是一系列列元素或from子句对象。似乎SQLAlchemy有时会通过执行bool(columns)来检查所传递的序列是否为空。解决方案是像创建subquery一样简单地按顺序包装它:

s = select([case(...)])

在混合属性的“ Python端”中,而不是计算任何file_id中最大的settlement_date是否恰好与实例匹配,您可以按实例的settlement_date进行过滤并检查最大值:

class Hdr(model.Base):

    @hybrid_property
    def is_latest(self):
        max_file_id = (
            object_session(self)
            .query(func.max(Hdr.file_id))
            .filter(Hdr.settlement_date == self.settlement_date)
            .scalar()
        )

        return max_file_id == self.file_id

在表达式中,您不需要将布尔表达式包装在标量子查询中,而是返回布尔表达式本身:

    @is_latest.expression
    def is_latest(cls):
        hdr_alias = aliased(Hdr)
        subquery = (
            select([func.max(hdr_alias.file_id)])
            .group_by(hdr_alias.settlement_date)
        )

        return cls.file_id.in_(subquery)