我正在使用 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/