简体   繁体   English

sqlalchemy hybrid_property和表达式

[英]sqlalchemy hybrid_property and expression

I can not understand the expressions. 我不明白这些表达。 How to get the following code to work? 如何使以下代码正常工作?

class OperationType(Enum):
    MINUS = 1
    MINUS_CORR = 2
    PLUS = 3
    PLUS_CORR = 4

group operation by type 按类型分组操作

BALANCE_PLUS_OPERATIONS = [
    OperationType.PLUS.value,
    OperationType.PLUS_CORR.value
]

BALANCE_MINUS_OPERATIONS = [
    OperationType.MINUS.value,
    OperationType.MINUS_CORR.value
]

Operation model 运作模式

class Operation(Model):

    __tablename__ = 'operation'

    id = db.Column(db.BigInteger, primary_key=True)
    created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow)
    operation_type = db.Column(db.SmallInteger, nullable=False)
    amount = Column(db.Integer, nullable=False)
    user_id = db.Column(db.ForeignKey('users.id'), nullable=False)
    user = relationship('User', backref='operation', uselist=False)

User model 用户模型

class User(UserMixin, Model):

    __tablename__ = 'users'

    id = Column(db.Integer, primary_key=True)
    operations = relationship("Operation", backref="users")

    @hybrid_property
    def balance(self):
        plus = sum(op.amount for op in self.operations if op.operation_type in BALANCE_PLUS_OPERATIONS)
        minus = sum(op.amount for op in self.operations if op.operation_type in BALANCE_MINUS_OPERATIONS)
        return plus - minus

    @balance.expression
    def balance(cls):
        p = select([func.sum(Operation.amount).label('BALANCE_PLUS_OPERATIONS')]) \
                .where(Operation.operation_type.in_(BALANCE_PLUS_OPERATIONS)) \
                .where(User.id == cls.id) \
                .as_scalar()
        m = select([func.sum(Operation.amount).label('BALANCE_MINUS_OPERATIONS')]) \
                .where(Operation.operation_type.in_(BALANCE_MINUS_OPERATIONS)) \
                    .where(User.id == cls.id) \
                    .as_scalar()
        return select([p - m]).label('BALANCE')

The expression is wrong and will produce the wrong result: 表达式错误,将产生错误的结果:

users = User.query.filter_by(balance=51).all()
for u in users:
    print(u, u.balance)

print: 打印:

<User(foo@bar.com)> 51
<User(bar@foor.com)> 0

but i expected only one record: 但我只希望有一个记录:

<User(foo@bar.com)> 51

Thanks 谢谢

I'll assume from context that the methods belong to the User class. 我将根据上下文假设这些方法属于User类。 In that light 鉴于此

.where(User.id == cls.id) \

is effectively 有效地

.where(User.id == User.id) \

or just where(True) , and so every user is joined with every operation, when it probably is meant to be something like where(True) ,因此每个用户都可以进行每个操作,而这可能意味着

.where(Operation.user_id == cls.id) \

though impossible to say due to lacking example. 尽管由于缺乏示例而无法说。 If the incorrect join does happen, it explains why the other user is returned by the query: it was joined with operations belonging to the correct user. 如果确实发生了不正确的联接,它说明了查询返回其他用户的原因:该联接是通过属于正确用户的操作进行联接的。

You also might have to add 您可能还需要添加

.correlate(cls) \

before as_scalar() . as_scalar()之前。 The outermost select is also redundant, I think. 我认为最外面的选择也是多余的。 You should be able to just 您应该能够

return (p - m).label('BALANCE')

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

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