我使用的数据库架构的关系并不总是正确的,而且我不确定如何用sqlalchemy的ORM来描述它。
此数据库中的所有主键都存储为blob类型,并且是16字节的二进制字符串。
我有一个名为attribute
的表,此表有一个名为data_type
的列。有许多内置data_type
,未在数据库中明确定义。因此,data_type
00
表示它是一个字符串,01
表示它是一个浮点数等(这些是十六进制值)。内置数据类型的最高值为12
(十进制为18)。
但是,对于attribute
中的某些行,存储在行中的属性值必须存在于预定义的值列表中。在这种情况下,data_type
引用lookup.lookup_id
。然后,可以从lookup.data_type
检索属性的实际数据类型。
我希望能够只拨打Attribue.data_type
并回复“' string'或者'数字'。显然我需要在某处定义{0x00: 'string', 0x01: 'number'}
映射,但是如果lookup.data_type
的值大于18,我怎么能告诉sqlalchemy我想要attribute.data_type
?
答案 0 :(得分:0)
有几种方法可以做到这一点。
到目前为止,最简单的方法是将预定义的数据类型放入表lookup
中。你说你“需要在某处定义......映射”,而且表格和任何地方一样好。
假设你不能这样做,下一个最简单的事情是在类Attribute上创建一个python property
。唯一的问题是你无法查询它。您需要重新分配列data_type
,以便它映射到_data_type
:
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_by(data_type='string')
,则需要将data_type映射到数据库可以处理的内容,即SQL语句。您可以在原始SQL中以CASE
表达式执行此操作:
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))
我不是100%肯定最后一部分会起作用;您可能需要显式连接表attribute
和lookup
以指定它是外连接,但我认为 SQLAlchemy默认情况下会这样做。这种方法的缺点是你总是试图加入表lookup
,但是要使用SQL进行查询,你必须这样做。
最后一个选项是使用多态,并将两种情况(data_type大于/小于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_on': _lookup
替换attribute.data_type > 18
,具体取决于ColumnProperty
何时被绑定。
正如你所看到的,这些都非常混乱。如果可能的话,做#1。