简体   繁体   English

sqlalchemy:hybrid_property的布尔表达式

[英]sqlalchemy: Boolean expression for hybrid_property

I have a sqlalchemy class that represents a table with columns FileID and SettlementDate . 我有一个sqlalchemy类,它表示具有FileIDSettlementDate列的表。 I want to create a hybrid property to say whether a given instance is the maximum FileID for its SettlementDate , and an associated expression to use when querying. 我想创建一个混合属性,以说给定实例是否为其SettlementDate的最大FileID以及查询时要使用的关联表达式。 I've successfully got the property working, but am struggling with the expression. 我已经成功地使该属性正常工作,但是在表达上却有些挣扎。 Here's the existing model: 这是现有模型:


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()
        )

I'd like to think I can do something along the lines of: 我想我可以按照以下方式做点事情:

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
    )
)

But this raises an error Boolean value of this clause is not defined . 但这会引发错误Boolean value of this clause is not defined

Any help would be greatly appreciated! 任何帮助将不胜感激!

Traceback follows: 追溯如下:

---------------------------------------------------------------------------
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

The problem is 问题是

s = select(case(...))

The first argument to select() should be a sequence of column elements or from clause objects. select()的第一个参数应该是列元素或from子句对象的序列。 It seems that SQLAlchemy at some point checks if the passed sequence is empty or not by doing bool(columns) . 似乎SQLAlchemy可以通过执行bool(columns)检查所传递的序列是否为空。 The solution is to simply wrap it in a sequence, as you have done in creating the subquery : 解决方案是将其简单地包装成一个序列,就像创建subquery所做的那样:

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

In the hybrid property's "Python side" instead of counting if the maximum file_id of any settlement_date happens to match the instance's you could filter by the instance's settlement_date and check against the maximum: 在混合属性的“ Python端”,而不是计算是否任何settlement_date的最大file_id恰好与实例相匹配,您可以按实例的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

In the expression you don't need to wrap the boolean expression in a scalar subquery, but return the boolean expression itself: 在表达式中,您不需要将布尔表达式包装在标量子查询中,而是返回布尔表达式本身:

    @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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM