2012-04-17 115 views
0

在下面的代碼我想更換* all_holdings *在帳戶中有一個叫做財產持有返回的* desired_holdings *(這是表示最新的已知量增持其可以隨時間變化)。我無法弄清楚如何構建關係調用。SQLAlchemy的 - 如何查詢轉換與子查詢到關係

另外在圖案的恰當任何意見(在一個表中保存的歷史數據,並使用最大日期子查詢以獲得最新的),更好的替代品,在查詢的改進表示讚賞。

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') 

回答

0

繼邁克爾·拜爾提供的答案後,我張貼到SQLAlchemy的谷歌組:

的desired_holdings()查詢是相當複雜的,我沒有通過試圖讓關係()來實現它而獲得勝利。關係()朝向保持兩個班,還不如多報告技術(以及任何與MAX()/ GROUP_BY它指的是報告)之間的持久性導向。

我會堅持@property上desired_holdings的頂部,使用object_session(個體經營)獲得一個「會話」,並完成。

此用例在http://docs.sqlalchemy.org/en/rel_0_7/orm/relationships.html#building-query-enabled-properties進行說明。