簡體   English   中英

SQLAlchemy:按關系中的關系字段排序

[英]SQLAlchemy: order by a relationship field in a relationship

在我正在研究的金字塔應用程序中,我有以下場景:

class Widget(Base):
    __tablename__ = 'widgets'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    sidebar = Column(mysql.TINYINT(2))

    def __init__(self, name, sidebar):
        self.name = name
        self.sidebar = sidebar

class Dashboard(Base):
    __tablename__ = 'dashboard'
    user_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
    widget_id = Column(Integer, ForeignKey('widgets.id'), primary_key=True)
    delta = Column(mysql.TINYINT)

    widget = relationship('Widget')

    def __init__(self, user_id, widget_id, delta):
        self.user_id = user_id
        self.widget_id = widget_id
        self.delta = delta 

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    login = Column(Unicode(255), unique=True)
    password = Column(Unicode(60))
    fullname = Column(Unicode(100))

    dashboard = relationship('Dashboard', order_by='Dashboard.widget.sidebar, Dashboard.delta')

    def __init__(self, login, password, fullname):
        self.login = login
        self.password = crypt.encode(password)
        self.fullname = fullname

因此,我希望用戶的“儀表板”關系具有用戶的儀表板記錄,但是由“側欄”(這是儀表板的關系屬性)排序。 目前我收到此錯誤:

sqlalchemy.exc.InvalidRequestError: Property 'widget' is not an instance of ColumnProperty (i.e. does not correspond directly to a Column).

在關系聲明中這種排序是否可行?

謝謝!

有了這個,試着想一想SQL SQLAlchemy在嘗試加載User.dashboard時應該發出什么。 就像SELECT * FROM dashboard JOIN widget ... ORDER BY widget.sidebar SELECT * FROM dashboard ORDER BY (SELECT sidebar FROM widget... ?通過不同的表對結果進行排序,對於relationship()的工作來說過於開放,以決定它自己。這可以通過提供的方式來實現在條件列表達式的Dashboard ,可以提供這種排序,當ORM發出簡單的SELECT對儀表板的表,以及當它是指它在一個不那么簡單,因為選擇在那里它可能跨用戶,儀表盤表加盟立刻(例如急切加載)。

我們提供自定義SQL表達式,特別是那些涉及其他表的表達式,使用column_property() ,或者當我們不希望默認情況下加載表達式時 或許在這種情況下可能 ,使用deferred( )。 例:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()

class Widget(Base):
    __tablename__ = 'widgets'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    sidebar = Column(Integer)

class Dashboard(Base):
    __tablename__ = 'dashboard'
    user_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
    widget_id = Column(Integer, ForeignKey('widgets.id'), primary_key=True)
    delta = Column(Integer)

    widget = relationship('Widget')

    widget_sidebar = deferred(select([Widget.sidebar]).where(Widget.id == widget_id))

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    login = Column(Unicode(255), unique=True)

    dashboard = relationship('Dashboard', order_by='Dashboard.widget_sidebar, Dashboard.delta')


e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)

w1, w2 = Widget(name='w1', sidebar=1), Widget(name='w2', sidebar=2)
s.add_all([
    User(login='u1', dashboard=[
        Dashboard(
            delta=1, widget=w1
        ),
        Dashboard(
            delta=2, widget=w2
        )
    ]),
])
s.commit()

print s.query(User).first().dashboard

“.dashboard”加載發出的最終SQL是:

SELECT dashboard.user_id AS dashboard_user_id, dashboard.widget_id AS dashboard_widget_id, dashboard.delta AS dashboard_delta 
FROM dashboard 
WHERE ? = dashboard.user_id ORDER BY (SELECT widgets.sidebar 
FROM widgets 
WHERE widgets.id = dashboard.widget_id), dashboard.delta

請記住,MySQL在為上述子查詢進行優化方面做得非常糟糕 如果您需要高性能,可以考慮將“側欄”的值復制到“儀表板”中,即使這會使一致性更難以維護。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM