Sqlalchemy 定义一个仅在某些情况下为真的关系()

Sqlalchemy 定义一个仅在某些情况下为真的关系(),sqlalchemy,Sqlalchemy,我使用的数据库模式的关系并不总是正确的,我不知道如何用sqlalchemy的ORM来描述它 此数据库中的所有主键都存储为blob类型,是16字节的二进制字符串 我有一个名为属性的表,这个表有一个名为数据类型的列。有许多内置的数据类型s未在数据库中明确定义。因此,可能00的data\u type表示它是一个字符串,01表示它是一个浮点值,等等(这些是十六进制值)。内置数据类型的最大值为12(十进制为18) 但是,对于属性中的某些行,该行中存储的属性值必须存在于预定义的值列表中。在这种情况下,dat

我使用的数据库模式的关系并不总是正确的,我不知道如何用sqlalchemy的ORM来描述它

此数据库中的所有主键都存储为blob类型,是16字节的二进制字符串

我有一个名为
属性
的表,这个表有一个名为
数据类型
的列。有许多内置的
数据类型
s未在数据库中明确定义。因此,可能
00的
data\u type
表示它是一个字符串,
01
表示它是一个浮点值,等等(这些是十六进制值)。内置数据类型的最大值为
12
(十进制为18)

但是,对于
属性
中的某些行,该行中存储的属性值必须存在于预定义的值列表中。在这种情况下,
data\u type
引用
lookup.lookup\u id
。然后可以从
查找中检索属性的实际数据类型。data\u type


我希望能够调用Attribue.data\u type
并返回“string”或“number”。显然,我需要在某个地方定义
{0x00:'string',0x01:'number'}
映射,但是如果
属性.data\u type
的值大于18,我如何告诉sqlalchemy我想要
查找.data\u type

  • 到目前为止,最简单的方法是将预定义的数据类型放入表
    lookup
    。你说你“需要在某个地方定义…映射”,而一个表就是一个很好的地方

  • 假设您不能这样做,下一个最简单的事情就是在class属性上创建一个python
    属性。唯一的问题是你不能对它进行查询。您需要重新指定列
    数据类型
    ,以便它映射到
    \u数据类型

    data_type_dict = {0x00: 'string',
                      0x01: 'number,
                      ...}
    
    class Attribute(Base):
    
        __tablename__ = 'attribute'
    
    
        _data_type = Column('data_type')
    
        ...
    
        @property
        def data_type(self):
            dt = data_type_dict.get(self._data_type, None)
            if dt is None:
                s = Session.object_session(self)
                lookup = s.query(Lookup).filter_by(id=self._data_type).one()
                dt = lookup.data_type
            return dt
    
  • 如果您希望它是可查询的,也就是说,如果您希望能够执行
    session.query(Attribute).filter\u by(data\u type='string')
    ,则需要将数据类型映射到数据库可以处理的对象,即SQL语句。您可以在原始SQL中作为
    大小写
    表达式执行此操作:

    from sqlalchemy.sql.expression import select, case
    
    class Attribute(Base):
    
        ...
    
        data_type = column_property(select([attribute, lookup])\
                                    .where(attribute.data_type==lookup.lookup_id)\
                                    .where(case([(attribute.data_type==0x00, 'string'),
                                                 (attribute.data_type==0x01, 'number'),
                                                 ...],
                                                else_=lookup.data_type))
    
    我不能百分之百肯定最后一部分会起作用;您可能需要显式地连接表
    属性
    查找
    ,以指定它是外部连接,尽管我认为默认情况下SQLAlchemy会这样做。这种方法的缺点是,您总是试图加入表
    查找
    ,尽管要使用SQL进行查询,您必须这样做

  • 最后一个选项是使用多态性,并将两种情况(数据类型大于/小于18)映射到两个不同的子类:

    class Attribute(Base):
        __tablename__ = 'attribute'
    
        _data_type = Column('data_type')
        _lookup = column_property(attribute.data_type > 18)
        __mapper_args__ = {'polymorphic_on': _lookup}
    
    class FixedAttribute(Attribute):
    
        __mapper_args__ = {'polymorphic_identity': 0}
    
        data_type = column_property(select([attribute.data_type])\
                                    .where(case([(attribute.data_type==0x00, 'string'),
                                                 (attribute.data_type==0x01, 'number'),
                                                 ...])))
    
    class LookupAttribute(Attribute):
    
        __mapper_args__ = {'polymorphic_identity': 1}
    
        data_type = column_property(select([lookup.data_type],
                                       whereclause=attribute.data_type==lookup.lookup_id))
    
    您可能必须用显式的
    属性替换
    'polymorphic\u on':\u lookup
    。数据类型>18
    ,具体取决于该
    列属性的绑定时间

  • 正如你所看到的,这些都非常混乱。如果可能的话,就去做