python - SQLAlchemy:如何扩展混合属性?

标签 python sql-server sqlalchemy

我正在使用 MSSQL 数据库,无法控制数据库设置或其中的(只读)数据。一张表在 SQLAlchemy 中表示如下:

class pdAnlage(pdBase):
    __tablename__ = "Anlage"
    typ = Column(CHAR(4), primary_key=True)
    nummer = Column(CHAR(4), primary_key=True)

在访问数据库时,我需要一个属性“name”,它只是“typ”和“nummer”的串联,它们之间有一个点。所以我这样做了:

    @hybrid_property
    def name(self):
        return self.typ + '.' + self.nummer

看起来很简单,并且按预期工作。但是有两个警告,一个是一般的,一个是特殊的。一般的:表很大,我想对 Anlage.name 进行查询,如下所示:

db.query(Anlage).filter(Anlage.name.like('A%.B'))
db.query(Anlage).filter(Anlage.name == 'X.Y')

这可行,但效率低下,因为 SQL 服务器在进行测试之前首先必须连接(大)表的所有“typ”和“nummer”列。所以我定义了这样一个类方法:

    @classmethod
    def name_like(self, pattern):
        p = pattern.split('.', 2)
        if len(p) == 1 or not p[1]:
            return self.typ.like(p[0])
        else:
            return and_(self.typ.like(p[0]), self.nummer.like(p[1]))

这并不优雅,但它可以很好地完成工作。重载“==”和“like()”会更好,有没有办法做到这一点?

现在来看特殊情况:name 和 typ 列都可以在数据库中包含尾随空格。但是 name 属性不能有空格,尤其是在点之前。所以我尝试像这样重写名称混合属性:

    @hybrid_property
    def name(self):
        return self.typ.rstrip() + '.' + self.nummer.rstrip()

这不起作用,因为 SQLAlchemy 不知道如何将 rstrip() python 方法转换为 MSSQL RTRIM() 函数。我怎样才能做到这一点?

最佳答案

你可以实现一个 custom comparator以特殊方式处理字符串操作数(以及其他必要方式):

from sqlalchemy.ext.hybrid import Comparator

_sep = '.'


def _partition(s):
    typ, sep, nummer = s.partition(_sep)
    return typ, nummer


class NameComparator(Comparator):

    def __init__(self, typ, nummer):
        self.typ = typ
        self.nummer = nummer
        super().__init__(func.rtrim(typ) + _sep + func.rtrim(nummer))

    def operate(self, op, other, **kwgs):
        if isinstance(other, str):
            typ, nummer = _partition(other)
            expr = op(self.typ, typ, **kwgs)

            if nummer:
                expr = and_(expr, op(self.nummer, nummer, **kwgs))

            return expr

        else:
            # Default to using the "slow" method of concatenating first that
            # hides the columns from the index created for the primary key.
            return op(self.__clause_element__(), other, **kwgs)

并将其与您的混合属性一起使用:

class pdAnlage(Base):
    __tablename__ = "Anlage"
    typ = Column(CHAR(4), primary_key=True)
    nummer = Column(CHAR(4), primary_key=True)

    @hybrid_property
    def name(self):
        return self.typ.rstrip() + _sep + self.nummer.rstrip()

    @name.comparator
    def name(cls):
        return NameComparator(cls.typ, cls.nummer)

关于python - SQLAlchemy:如何扩展混合属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52662760/

相关文章:

python - SQLAlchemy 计算所有行,我想要特定行

sql-server - freetds 和 pyodbc 无法连接

sql - 在 SSIS 中获取 OLEDB 连接错误

python - 处理 SQL Alchemy session 。

python - 无法迭代二维数组来标准化数据

python - 按重叠范围对行进行分组

python - 使用 SqlAlchemy 在无限循环中获取新结果

python - SQLAlchemy监听多对多关系中的属性变化并更改initiator的其他属性

python - 如何对一维 numpy 数组进行下采样?

sql - 将时间结果转换为 SQL Server 中的个位数值