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

发布于 2024-11-08 17:29:34 字数 395 浏览 0 评论 0原文

我有一个类保存我在屏幕上绘制的内容的大小和位置。我使用 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()

是否有某种方法使用集合或关联代理来获得我想要的行为?

I have a class that holds the size and position of something I draw to the screen. I am using sqlalchemy with a sqlite database to persist these objects. However, the position is a 2D value (x and y) and I'd like to have a convienent way to access this as

MyObject.pos # preferred, simpler interface

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

I can use properties but this solution isn't optimal since I cannot query based on the properties

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

Is there some way to use collections or association proxies to get the behavior I want?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

羁拥 2024-11-15 17:29:34

如果您使用 PostGISpostgres),您可以使用 GeoAlchemy,它允许您根据 PostGIS 中可用的几何基元定义列类型。其中一种数据类型是Point,顾名思义。

PostGIS 比普通 PostgreSQL 更难设置,但如果您确实打算根据实际几何术语进行查询,那么额外的(大部分是一次性的)麻烦是值得的。

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


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

您可能想要一个积分课程。一个不错的选择实际上是使用
一个命名元组,因为您不必担心代理分配
的个体坐标。该属性要么全部分配,要么全部不分配,

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')

If you are using PostGIS (Geometry extended version of postgres), you can take advantage of that using GeoAlchemy, which allows you to define Column types in terms of geometric primitives available in PostGIS. One such data type is Point, which is just what it sounds like.

PostGIS is a bit more difficult to set up than vanilla PostgreSQL, but if you actually intend to do queries based on actual geometric terms, it's well worth the extra (mostly one time) trouble.

Another solution, using plain SQLAlchemy is to define your own column types with the desired semantics, and translate them at compile time to more primitive types supported by your database.


Actually, you could use a property, but not with the builtin property decorator. You'd have to have to work a little harder and create your own, custom descriptor.

You probably want a point class. A decent option is actually to use
a namedtuple, since you don't have to worry about proxying assignment
of individual coordinates. The property gets assigned all or nothing

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

This would let us at least compare point values. The next step in
writing the descriptor is to work through its methods. There are two methods to think about, __get__
and __set__, and with get, two situations, when called on
an instance, and you should handle actual point values, and when
called on the class, and you should turn it into a column expression.

What to return in that last case is a bit tricky. What we want is something
that will, when compared to a point, returns a column expression that equates
the individual columns with the individual coordinates. well make one more
class for that.

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)

All that's left is to define the actual descriptor class.

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))

which could be used thusly:

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

    pos = PointProperty('x', 'y')
哆啦不做梦 2024-11-15 17:29:34

使用 PickleType 列类型定义表。然后它会自动保留 Python 对象,只要它们是可pickle的。元组是可腌制的。

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

Define your table with a PickleType column type. It will then automatically persist Python objects, as long as they are pickleable. A tuple is pickleable.

mytable = Table("mytable", metadata,
       Column('pos', PickleType(),
        ...
)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文