2017-02-20 113 views
0

我有一个多对一的关系数据库。在我的声明系统中,我打电话给relationship(),如下例所示。出于某种原因,我想保留所有Features排序。不幸的是,排序逻辑非常复杂,并且使用多个属性来完成。如何在SQLAlchemy关系()中使用sortedcontainers.SortedList?

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()的说法order_by但我的使用情况是更复杂,因为排序使用几个列的值。

那么,有没有我错过了使用SQLAlchemy或我应该尝试找到一种解决方法?

回答

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 

很显然,我们呼吁SortedListappend。如果该值违反排序顺序,则从documentation,append引发ValueError。

基本上解决办法是重写方法:

class SuperSortedList(SortedList): 
    def append(self, item): 
     self.add(item) 

这似乎甚至在我的现实生活中的例子工作。但是,重写所有这类方法(例如insert)可能是一个好主意。