我有一个多对一关系的数据库。在我的声明系统中,我调用relationship(),如下面的最小示例所示。出于某种原因,我想保持所有Features
排序。不幸的是,排序逻辑非常复杂,使用了几个属性。
from sortedcontainers import SortedList
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, Text
from sqlalchemy import ForeignKey
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Product(Base):
__tablename__ = 'products'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(Text)
class Feature(Base):
__tablename__ = 'features'
id = Column(Integer, primary_key=True, autoincrement=True)
productid = Column(Integer, ForeignKey('products.id'))
attr = Column(Integer)
product = relationship('Product', back_populates='features')
Product.features=relationship('Feature', collection_class=SortedList, back_populates='product')
def __eq__(self, other):
# some magic here, simplified...
return self.attr == other.attr
def __lt__(self, other):
# some magic here, simplified...
return self.attr < other.attr
def __le__(self, other):
# some magic here, simplified...
return self.attr <= other.attr
engine = create_engine('sqlite:///test.db')
Session = sessionmaker(bind=engine)
Base.metadata.create_all(engine)
我的数据库已经填充了以下值:
sqlite> select * from products;
id name
---------- ----------
1 Product1
sqlite> select * from features;
id productid attr
---------- ---------- ----------
1 1 42
2 1 1
当我尝试加载(通过访问)这些值时,sortedcontainers.SortedList引发了一个ValueError异常,可能是因为它试图加载无序结果。当功能存储有序时,没有问题。
In [1]: from test import *
In [2]: session = Session()
In [3]: p = session.query(Product).first()
In [4]: for f in p.features:
print("id: %d\tattr: %d" % (f.id, f.attr))
...:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
# traceback
ValueError: <test.Feature object at 0x7f68da5d2208> not in sort order at index 1
我知道在这种特殊情况下,解决方案是使用带有参数relationship
的{{1}}()但我的用例更复杂,因为排序使用了几列的值。
那么,有没有我错过使用SQLAlchemy或我应该尝试找到一个解决方法?
答案 0 :(得分:0)
是的,我终于找到了一个非常简单的解决方案来查看回溯:
/usr/lib/python3/dist-packages/sqlalchemy/orm/collections.py in append(self, item, _sa_initiator)
1072 def append(self, item, _sa_initiator=None):
1073 item = __set(self, item, _sa_initiator)
-> 1074 fn(self, item)
1075 _tidy(append)
1076 return append
/usr/lib/python3/dist-packages/sortedcontainers/sortedlist.py in append(self, val)
1026 if val < _lists[pos][-1]:
1027 msg = '{0} not in sort order at index {1}'.format(repr(val), self._len)
-> 1028 raise ValueError(msg)
1029
1030 _maxes[pos] = val
显然,我们在append
上呼叫SortedList
。如果值违反排序顺序,则从documentation append
引发ValueError。
基本上解决方案是覆盖该方法:
class SuperSortedList(SortedList):
def append(self, item):
self.add(item)
这似乎甚至在我的现实生活中也起作用。不过,覆盖所有类型的方法(例如insert
)可能是个好主意。