1

all_holdings以下のコードでは、Accountを、holdingsを返すというプロパティに置き換えたいと思いますdesired_holdings(これは、時間の経過とともに変化する可能性のある最新の既知の数量を表す保有物です)。私は関係への呼び出しを構築する方法を理解するのに苦労しています。

さらに、パターンの適切性(履歴データを単一のテーブルに保持し、最大日付サブクエリを使用して最新のものを取得する)、およびクエリのより良い代替案や改善についてのコメントをいただければ幸いです。

from sqlalchemy import Column, Integer, String, Date, DateTime, REAL, ForeignKey, func
from sqlalchemy.orm import relationship, aliased
from sqlalchemy.sql.operators import and_, eq
from sqlalchemy.ext.declarative import declarative_base
from db import session
import datetime
import string

Base = declarative_base()

class MySQLSettings(object):
    __table_args__ = {'mysql_engine':'InnoDB'}

class Account(MySQLSettings, Base):
    __tablename__ = 'account'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))
    all_holdings = relationship('Holding', backref='account')

    def desired_holdings(self):
        max_date_subq = session.query(Holding.account_id.label('account_id'),
                                      Holding.stock_id.label('stock_id'),
                                      func.max(Holding.as_of).label('max_as_of')). \
                                      group_by(Holding.account_id, Holding.stock_id).subquery()

        desired_query = session.query(Holding).join(Account,
                                                    Account.id==account.id).join(max_date_subq).\
                                                    filter(max_date_subq.c.account_id==account.id).\
                                                    filter(Holding.as_of==max_date_subq.c.max_as_of).\
                                                    filter(Holding.account_id==max_date_subq.c.account_id).\
                                                    filter(Holding.stock_id==max_date_subq.c.stock_id)

        return desired_query.all()

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

class Stock(MySQLSettings, Base):
    __tablename__ = 'stock'
    id = Column(Integer, primary_key=True)
    name = Column(String(64))

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

class Holding(MySQLSettings, Base):
    __tablename__ = 'holding'
    id = Column(Integer, primary_key=True)
    account_id = Column(Integer, ForeignKey('account.id'), nullable=False)
    stock_id = Column(Integer, ForeignKey('stock.id'), nullable=False)
    quantity = Column(REAL)
    as_of = Column(Date)

    stock = relationship('Stock')

    def __str__(self):
        return "Holding(%f, '%s' '%s')"%(self.quantity, self.stock.name, str(self.as_of))

    def __init__(self, account, stock, quantity, as_of):
        self.account_id = account.id
        self.stock_id = stock.id
        self.quantity = quantity
        self.as_of = as_of

if __name__ == "__main__":
    ibm = Stock('ibm')
    session.add(ibm)
    account = Account('a')
    session.add(account)
    session.flush()
    session.add_all([ Holding(account, ibm, 100, datetime.date(2001, 1, 1)),
                      Holding(account, ibm, 200, datetime.date(2001, 1, 3)),
                      Holding(account, ibm, 300, datetime.date(2001, 1, 5)) ])
    session.commit()

    print "All holdings by relation:\n\t", \
        string.join([ str(h) for h in account.all_holdings ], "\n\t")

    print "Desired holdings query:\n\t", \
        string.join([ str(h) for h in account.desired_holdings() ], "\n\t")

実行時の結果は次のとおりです。

All holdings by relation:
    Holding(100.000000, 'ibm' '2001-01-01')
    Holding(200.000000, 'ibm' '2001-01-03')
    Holding(300.000000, 'ibm' '2001-01-05')
Desired holdings query:
    Holding(300.000000, 'ibm' '2001-01-05')
4

1 に答える 1

2

sqlalchemy google groupに投稿した後、Michael Bayerから提供された次の回答:

desired_holdings()クエリは非常に複雑であり、relationship()にそれを実行させようとしても、成功は見られません。Relationship()は、2つのクラス間の永続性を維持することを目的としており、レポート手法(およびmax()/ group_byを含むものはすべてレポートを参照しています)ではありません。

@propertyをdesired_holdingsの上に貼り付け、object_session(self)を使用して「セッション」に到達し、完了します。

クエリが有効なプロパティの詳細を参照してください。

于 2012-05-01T18:40:05.787 に答える