SQLAlchemy/PostgreSQL 可变的、去重数组

SQLAlchemy/PostgreSQL mutable, deduplicated array

在阅读了关于使用 PostgreSQL 实现标签的 article 之后,我决定使用 PostgreSQL 的数组数据类型。

但据我了解,SQLAlchemy 中没有对可变数组的任何内置支持。我还想防止这些数组中出现重复项(PostgreSQL 中没有任何内置 'set-like' 数据类型)。

我很难找到任何具体示例来说明如何使用和操作 PostgreSQL 支持的 SQLAlchemy 数组(以声明方式),即使是简单的 append/update 操作也是如此。我将如何设置 ARRAY 并将其附加到(如果要附加的字符串不是重复的)SQLAlchemy ARRAY 数据类型?

我运行正好遇到这个问题。我使用的解决方案是创建一个继承自 sqlalchemy.ext.mutable.Mutableset 的类型,然后将其包装在由 sqlalchemy.dialects.postgresql.ARRAY.

支持的类型中
from sqlalchemy.ext.mutable import Mutable
from sqlalchemy.dialects.postgresql import ARRAY

modmethods = ['add', 'clear', 'difference_update', 'discard', 
              'intersection_update', 'pop', 'remove',
              'symmetric_difference_update', 'update',
              '__ior__', '__iand__', '__isub__', '__ixor__']

class MutableSet(Mutable, set):
    @classmethod
    def coerce(cls, key, value):
        if not isinstance(value, cls):
            return cls(value)
        else:
            return value

def _make_mm(mmname):
    def mm(self, *args, **kwargs):
        try:
            retval = getattr(set, mmname)(self, *args, **kwargs)
        finally:
            self.changed()
        return retval
    return mm

for m in modmethods:
    setattr(MutableSet, m, _make_mm(m))

del modmethods, _make_mm

def ArraySet(_type, dimensions=1):
    return MutableSet.as_mutable(ARRAY(_type, dimensions=dimensions))

这会覆盖 set 的方法,这些方法可以通过添加对 Mutablechanged 方法的调用来更改集合的值,导致 SQLAlchemy 将可能更改的值刷新到数据库。

然后,您在 SQLAlchemy 中使用将包含在其中的类型声明此类型;例如,将其声明为一组整数:

Column(ArraySet(Integer))

然后,当您使用它时,您可以像对待标准 Python 集一样对待该值,所有运算符和方法都保持不变。