SQLAlchemy python order_by parent 的 parent 的属性

SQLAlchemy python order_by parent's parent's attribute

我在订购时遇到了困难。我有一个 3 深度关系如下:

fight 1->M participant 1->M action

我需要按战斗 ID 排序动作列表。我找不到办法做到这一点。

class fight(db.Model):
    fight_id = db.Column(db.Integer, primary_key=True)
    fight_name = db.Column('fight_name')

class participant(db.Model):
    participant_id = db.Column(db.Integer, primary_key=True)
    participant_name = db.Column('participant_name')
    fight_id = db.Column(db.Integer, db.ForeignKey("fight.fight_id"))
    fight = db.relationship('fight', innerjoin=True)

class action(db.Model):
    action_id = db.Column(db.Integer, primary_key=True)
    participant_party_1 = db.Column(db.Integer, db.ForeignKey("participant.participant_id"))
    participant_1 = db.relationship('participant', foreign_keys=[participant_1])
    participant_party_2 = db.Column(db.Integer, db.ForeignKey("participant.participant_id"))
    participant_2 = db.relationship('participant', foreign_keys=[participant_2])

我正在尝试做这样的事情?

action.query.order_by(action.<participant>.<fight_id>).all()

我真的需要 participant_1 和 participant_2 也完成。

您需要加入 Participant 模型,然后才能在查询中使用它。我按 DESC 对战斗 ID 进行了排序,以确保它正常工作。

q = session.query(Action).join(Action.participant_1).order_by(Participant.fight_id.desc(), Action.participant_party_1, Action.participant_party_2)

这是一个更大的例子,我更改了一些模型,因为我在运行时遇到了问题:

from datetime import datetime, date
from sqlalchemy import (
    create_engine,
    Text,
    Integer,
    String,
    ForeignKey,
    UniqueConstraint,
    update,
    DateTime,
   Date,
    Boolean,
    LargeBinary,
    nullslast,
    Index,
)
from sqlalchemy.schema import (
    Table,
    Column,
    MetaData,
)
from sqlalchemy.sql import select, and_, or_, func
from sqlalchemy.orm import declarative_base, relationship
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError

metadata = MetaData()
Base = declarative_base(metadata=metadata)

engine = create_engine('postgresql+psycopg2://username:password@/dbname', echo=False)

class Fight(Base):
    __tablename__ = "fights"
    id = Column(Integer, primary_key=True)
    name = Column(String)

class Participant(Base):
    __tablename__ = "participants"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    fight_id = Column(Integer, ForeignKey("fights.id"))
    fight = relationship('Fight', innerjoin=True)

class Action(Base):
    __tablename__ = "actions"
    id = Column(Integer, primary_key=True)
    participant_party_1 = Column(Integer, ForeignKey("participants.id"))
    participant_1 = relationship('Participant', foreign_keys=[participant_party_1])
    participant_party_2 = Column(Integer, ForeignKey("participants.id"))
    participant_2 = relationship('Participant', foreign_keys=[participant_party_2])


Base.metadata.create_all(engine)

with Session(engine) as session:
    f1 = Fight(name="Sunday")
    session.add(f1)
    f2 = Fight(name="Monday")
    session.add(f2)
    p1 = Participant(name="P1", fight=f1)
    p2 = Participant(name="P2", fight=f1)
    p3 = Participant(name="P3", fight=f2)
    p4 = Participant(name="P4", fight=f2)
    session.add_all([p1, p2, p3, p4])
    for action in range(5):
        session.add(Action(participant_1=p1, participant_2=p2))
    for action in range(3):
        session.add(Action(participant_1=p3, participant_2=p4))

    q = session.query(Action).join(Action.participant_1).order_by(Participant.fight_id.desc(), Action.participant_party_1, Action.participant_party_2)

    for action in q.all():
        print (action.participant_1.fight_id, action.participant_party_1, action.participant_party_2, action.id)

更大示例的输出

2 3 4 6
2 3 4 7
2 3 4 8
1 1 2 4
1 1 2 1
1 1 2 5
1 1 2 2
1 1 2 3

这对我来说不是完整的答案,但它是正确的方法。

action.query.join(participant, action.participant_party_1 == participant.participant_id).join(fight, participant.fight_id == fight.fight_id).order_by(fight.fight_id).order_by(action.attack_order).all()

非常感谢@IanWilson,但我为我的情况找到了一个更简单的答案。你让我找对地方了。