我有一个类,它包含我绘制到屏幕上的东西的大小和位置。我使用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()
有没有办法使用集合或关联代理来获得我想要的行为?
答案 0 :(得分:4)
如果您使用PostGIS(postgres的几何扩展版本),您可以使用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(),
...
)