Sqlalchemy 选择条件

4 投票
1 回答
4031 浏览
提问于 2025-04-17 04:45

我在一个表上有一个映射器,我想定义一个列属性,这个属性应该根据实体是否具有某个特性来选择是“真”还是“假”。

mapper( Person, persons_table, properties = {
    'administrator': column_property( 
        select( 
            [True if roles_table.c.is_admin or roles_table.c.id == 1 else False],
            roles_table.c.id == persons_table.c.role_id
        ).label( 'administrator' )
        )
} )

我能做到这一点吗?我更感兴趣的是这一部分:[True if roles_table.c.is_admin or roles_table.c.id == 1 else False],这段代码让我可以根据条件给这个列设置一个值。

1 个回答

4

你的SELECT表达式实际上是一个Python表达式:

select([True if roles_table.c.is_admin or roles_table.c.id == 1 else False],
       roles_table.c.id == persons_table.c.role_id)

sqlalchemy.select()会把它看作:

select([True], some_expression_object)

因为列对象roles_table.c.is_admin在布尔上下文中会被评估为True。我不太清楚SQLAlchemy会怎么理解这个,但肯定不会按照你想的那样工作。

你需要重写这个表达式,使它符合普通SQL的格式,使用sqlalchemy.sql.expression.case()来代替if ... else ...

column_property(
    select([case([(roles_table.c.is_admin, 1),
                  (roles_table.c.id == 1, 1)], else_=0)],
           roles_table.c.id == persons_table.c.role_id))

不过在你的情况下,可能有一个更简单的解决方案。PersonRole之间似乎有一个N:1的关系(一个人只有一个角色)。我猜这里有一个orm.relationship Person.role来获取一个人的角色。

为什么不直接添加一个普通的Python属性呢:

class Person:
    # ...

    @property
    def administrator(self):
        return self.role and (self.role.is_admin or self.role.id == 1)

撰写回答