在连锁关系中按列排序

时间:2016-10-17 21:27:50

标签: python sqlalchemy sql-order-by relation

在我的应用程序中,我有这样的模型:

class A(Base):
    id = Column(UUID, primary_key=True)
    name_a = Column(Text)

class B(Base):
    id = Column(UUID, primary_key=True)
    name_b = Column(Text)
    parent_a_id = Column(UUID, ForeignKey(A.id))
    parent_a = relationship(A, lazy='joined')

class C(Base):
    id = Column(UUID, primary_key=True)
    name_c = Column(Text)
    parent_b_id = Column(UUID, ForeignKey(B.id))
    parent_b = relationship(B, lazy='joined')

当我这样做时:

DBSession().query(C).all()

它工作正常 - 我在一个LEFT OUTER JOIN查询中得到所有带有B和A名称的C名称。

但我想知道如何通过以下方式排序 name_a,name_b,name_c

我正在尝试做类似的事情:

DBSession().query(C).order_by(
    C.parent_b.parent_a.name_a,
    C.parent_b.name_b,
    C.name_c
).all()

此类代码不起作用。如何用sqlalchemy精神来完成它?

1 个答案:

答案 0 :(得分:2)

我玩了你的样本并使用PostgreSQL来增加积分。

您的查询返回C对象列表,传统上在SQL中,您只能按检索的列进行排序。在幕后检索关系,所以我不明白为什么应该可以按它们排序。

从好的方面来说,一旦检索到列表,它就会在你的内存中附带整个层次结构,因此你可以超快速地在内存中对它进行排序:

clist = session.query(C).all()
sorted(clist, key=lambda c:(c.b.a.name, c.b.name, c.name))

我找到的另一个解决方案是对parameter使用order_by relationship

class B(Base):
   ...
   a = relationship(A, order_by="A.name", lazy='joined')

class C(Base):
   ...
   b = relationship(B, order_by="B.name", lazy='joined')

最终结果:

print (session.query(C).order_by(C.name) )
  

ORDER BY tc.name,tb_1.name,ta_1.name

这与你想要的很接近,但你需要反转列表才能按A.name, B.name, C.name顺序获得它。

P.S。:我的确切类定义供参考:

#!/usr/bin/env python
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, ForeignKey, create_engine, Text
from sqlalchemy.orm import relationship

engine_connect_str = "postgresql://postgres@MYSERV/mydb"
engine = create_engine(engine_connect_str, echo=False)
Session = sessionmaker(engine)
session = Session()
Base = declarative_base()


class A(Base):
    __tablename__ = 'ta'
    id = Column('id', Integer, primary_key=True)
    name = Column(Text)

    def __repr__(self):
        return "{}(id={}, name='{}')".format(self.__class__.__name__, self.id, self.name)

class B(Base):
    __tablename__ = 'tb'    
    id = Column('id', Integer,primary_key=True)
    name = Column(Text)
    a_id = Column('aid', ForeignKey(A.id), nullable=False)

    a = relationship(A, order_by="A.name", lazy='joined')

    def __repr__(self):
        return "{}(id={}, name='{}', a_id={})".format(self.__class__.__name__, self.id, self.name, self.a_id)

class C(Base):
    __tablename__ = 'tc'    
    id = Column('id', Integer, primary_key=True)
    name = Column(Text)
    b_id = Column('bid', ForeignKey(B.id), nullable=False)

    b = relationship(B, order_by="B.name", lazy='joined')

    def __repr__(self):
        return "{}(id={}, name='{}', b_id={})".format(self.__class__.__name__, self.id, self.name, self.b_id)