【问题标题】:How do you apply exponential operations to computed columns in SQLAlchemy?如何将指数运算应用于 SQLAlchemy 中的计算列?
【发布时间】:2021-08-01 01:20:18
【问题描述】:

我想在我的 SQLAlchemy 模型类上定义一个计算列。但是,对于某些运算符(例如加法)而不是其他运算符(例如指数),似乎 Column 类已重载。下面是我的意思的一个非常粗略的例子。

from sqlalchemy import Column, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import column_property

Base = declarative_base()

class MyModel(Base):

    __tablename__ = "my_model"

    id = Column(Integer, primary_key=True)

    addition = column_property(id + 2)  # Totally fine
    exponent = column_property(id ** 2)  # TypeError

TypeError:** 或 pow() 不支持的操作数类型:'Column' 和 'int'

我对 SQLAlchemy 比较陌生,所以我可能会被误导。这似乎是一个非常简单的用例,但到目前为止我还没有找到太多关于如何完成它的信息。

【问题讨论】:

    标签: python python-3.x sqlite sqlalchemy


    【解决方案1】:

    您可以使用 ORM 事件,而不是尝试根据其他列的值设置约束。事件在特定时间执行,允许在数据库行的列上运行函数并可能更改属性的值。

    您可以使用每次尝试在数据库中提交对象时发送的before_commit 事件。

    # Import event from SQLAlchemy
    from sqlalchemy import event
    
    # Your code
    from sqlalchemy import Column, Integer
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy.orm import column_property
    
    Base = declarative_base()
    
    class MyModel(Base):
    
        __tablename__ = "my_model"
    
        id = Column(Integer, primary_key=True)
    
        addition = Column(Integer)    # Set your fields as normal Integer without constraints
        exponent = Column(Integer)    # Set your fields as normal Integer without constraints
    
    
    # Create an event to be executed before commit
    @event.listens_for(Table, 'before_commit')
    def make_constraints(mapper, connect, target):
        # target is an instance of MyModel
        target.addition = target.id + 1
        target.exponent = target.id ** 2
    

    查看 ORM 事件的文档:https://docs.sqlalchemy.org/en/14/orm/events.html

    如果你真的需要一些数据库级别的约束,你可以在你的表上设置一个CheckConstraint

    【讨论】:

    • 谢谢,我喜欢这个想法,但我认为对于我的用例,最好是真正计算字段而不是实际存储在数据库中。我想轻松调整计算,而无需迁移现有行以反映该调整。我知道混合属性 + 表达式,但不太热衷于将计算定义为 Python 和 SQL 表达式的想法。我宁愿只使用表达式,这就是我尝试使用 column_property 的原因。
    • 您的意思是结果不必存储在数据库中?
    【解决方案2】:

    只需使用expression.func 正确定义计算列:

    class MyModel(Base):
        __tablename__ = "my_model"
        # ...
        exponent = column_property(func.pow(id, 2))
    

    【讨论】:

      猜你喜欢
      • 2013-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多