使用sqlalchemy在sqlite数据库中存储列表/元组

时间:2011-05-23 03:45:04

标签: python sqlite sqlalchemy

我有一个类,它包含我绘制到屏幕上的东西的大小和位置。我使用sqlalchemy和sqlite数据库来持久保存这些对象。但是,该位置是一个2D值(x和y),我希望有一种方便的方式来访问它

MyObject.pos # preferred, simpler interface

# instead of: 
MyObject.x 
MyObject.y # inconvenient

我可以使用属性,但此解决方案不是最佳的,因为我无法根据属性进行查询

session.query(MyObject).filter(MyObject.pos==some_pos).all()

有没有办法使用集合或关联代理来获得我想要的行为?

2 个答案:

答案 0 :(得分:4)

如果您使用PostGISpostgres的几何扩展版本),您可以使用GeoAlchemy来利用它,这允许您根据可用的几何图元定义列类型在PostGIS中。一种这样的数据类型是Point,这听起来就像它。

PostGIS比vanilla PostgreSQL设置起来要困难一些,但如果你真的打算根据实际的几何术语进行查询,那么额外的(大部分是一次性的)麻烦都是值得的。

使用普通SQLAlchemy的另一个解决方案是define your own column types具有所需的语义,并在编译时将它们转换为数据库支持的更原始类型。


实际上,您可以使用属性,但不能使用内置的property装饰器。你必须要努力工作并创建自己的自定义描述符。

你可能想要一个点类。实际上是一个不错的选择 一个namedtuple,因为你不必担心代理分配 个别坐标该属性被分配全部或全部

Point = collections.namedtuple('Point', 'x y')

这将让我们至少比较点值。下一步 编写描述符是为了解决它的方法。有两种方法可以考虑,__get____set__,以及get,两种情况,当被召唤时 一个实例,你应该处理实际的点值,以及何时 调用了,你应该把它变成一个列表达式。

在最后一个案例中返回的内容有点棘手。我们想要的是什么 与点相比,它将返回等于的列表达式 具有单独坐标的各列。好好再做一个 为此而上课。

class PointColumnProxy(object):
    def __init__(self, x, y):
        ''' these x and y's are the actual sqlalchemy columns '''
        self.x, self.y = x, y

    def __eq__(self, pos):
        return sqlalchemy.and_(self.x == pos.x,
                               self.y == pos.y)

剩下的就是定义实际的描述符类。

class PointProperty(object):
    def __init__(self, x, y):
        ''' x and y are the names of the coordinate attributes '''
        self.x = x
        self.y = y

    def __set__(self, instance, value):
        assert type(value) == Point
        setattr(instance, self.x, value.x)
        setattr(instance, self.y, value.y)


    def __get__(self, instance, owner):
        if instance is not None:
            return Point(x=getattr(instance, self.x),
                         y=getattr(instance, self.y))
        else: # called on the Class
            return PointColumnProxy(getattr(owner, self.x),
                                    getattr(owner, self.y))

可以这样使用:

Base = sqlalchemy.ext.declarative.declarative_base()
class MyObject(Base):
    x = Column(Float)
    y = Column(Float)

    pos = PointProperty('x', 'y')

答案 1 :(得分:0)

使用PickleType列类型定义表。然后它会自动持久化Python对象,只要它们是pickleable。元组是可选择的。

mytable = Table("mytable", metadata,
       Column('pos', PickleType(),
        ...
)