我有一个类,用于保存我在屏幕上绘制的内容的大小和位置。我使用 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()
是否有某种方法可以使用集合或关联代理来获得我想要的行为?
最佳答案
如果您使用PostGIS ( postgres 的几何扩展版本),您可以使用 GeoAlchemy 来利用它,它允许您根据 PostGIS 中可用的几何基元定义列类型。其中一种数据类型是Point
,顾名思义。
PostGIS 比普通 PostgreSQL 更难设置,但如果您确实打算根据实际几何术语进行查询,那么额外的(大部分是一次性的)麻烦是值得的。
另一个解决方案,使用普通的 SQLAlchemy 是 define your own column types具有所需的语义,并在编译时将它们转换为数据库支持的更原始类型。
实际上,您可以使用属性,但不能使用内置 property
装饰器。您必须更加努力地工作并创建您自己的自定义描述符。
您可能想要一个积分类(class)。一个不错的选择实际上是使用 一个命名元组,因为您不必担心代理分配 的个体坐标。该属性要么全部分配,要么全部不分配
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')
关于python - 使用 sqlalchemy 在 sqlite 数据库中存储列表/元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6092616/