SQLAlchemy中“一對多”場景下的排序取數

Python操作數據庫表時常用SQLAlchemy做ORM,把關係數據庫的表結構映射到對象上,並通過relationship做外鍵關聯,方便進一步處理。

假設需要實現某個“一對多”的場景,從“一”這頭需要取出“多”那頭的全部對象,並按某個字段做排序,如何實現呢?

話不多說,show code。

本例使用sqlite3做數據庫,創建Project和User兩張表,兩者是一對多關係。
核心是在User表中通過backref做反向引用時聲明order_by即可。

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, backref, foreign, relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Project(Base):
    __tablename__ = "project"

    id = Column(Integer, primary_key=True)
    name = Column(String(20))

    def __repr__(self):
        return "<Project(id='%d', name='%s')>" % (self.id, self.name)


class User(Base):
    __tablename__ = "user"

    id = Column(Integer, primary_key=True)
    name = Column(String(20))
    project_id = Column(Integer)
    project = relationship(Project, primaryjoin=foreign(project_id) == Project.id,
                             backref=backref("users", order_by=id.desc()))

    def __repr__(self):
        return "<User(id='%d', name='%s', project_id='%d')>" % (self.id, self.name, self.project_id)


#  init database and create tables
def init_db():
    engine = create_engine('sqlite:///test.db')
    smaker = sessionmaker(bind=engine)
    session = smaker()

    Base.metadata.create_all(engine)
    return engine, smaker, session


#  prepare data
def init_data(session):
    project = Project(name='Project_A')
    session.add(project)
    session.commit()

    user_a = User(name='user_a', project_id=project.id)
    user_b = User(name='user_b', project_id=project.id)
    session.add_all([user_a, user_b])
    session.commit()


def main():
    engine, smaker, session = init_db()
    init_data(session)

    # test 
    projects = session.query(Project).all()
    for p in projects:
        print(p.users)


if __name__ == '__main__':
    main()

結果如圖,可以看到User對象是按照id倒序排列。


參考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章