2012-04-10 98 views
2

看看帖子的底部,你可以看到我有三個類。這裏的代碼是即時編寫的僞代碼,未經測試,但它充分顯示了我的問題。如果我們需要實際的課程,我明天可以在工作時更新這個問題。因此,忽略語法問題和只代表思想的代碼,而不是那些能夠做我在那裏描述的實際「代碼」。sqlalchemy訪問父類的屬性

問題1 如果你看看Item搜索類的方法,你可以看到,當用戶進行搜索時,我調用基類的搜索,然後基於該結果返回正確的類/對象。這工作,但似乎kludgy。有一個更好的方法嗎?

問題2 如果你看看KitItem類,你可以看到我重寫了標價。如果標誌calc_list設置爲true,那麼我將這些組件的標價結合起來並作爲套件的標價返回。如果它沒有標記爲真,我想返回「基準」目錄價格。但據我所知,無法訪問父屬性,因爲在正常的設置中,這將是沒有意義的,但使用sqlalchemy和共享表繼承可能會有用。

TIA

class Item(DeclarativeBase): 
    __tablename__ = 'items' 
    item_id = Column(Integer,primary_key=True,autoincrement=True) 
    sku = Column(Unicode(50),nullable=False,unique=True) 
    list_price = Column(Float) 
    cost_price = Column(Float) 
    item_type = Column(Unicode(1)) 
    __mapper_args__ = {'polymorphic_on': item_type} 
    __ 
    def __init__(self,sku,list_price,cost_price): 
     self.sku = sku 
     self.list_price = list_price 
     self.cost_price = cost_price 

    @classmethod 
    def search(cls): 
     """ 
     " search based on sku, description, long description 
     " return item as proper class 
     """ 
     item = DBSession.query(cls).filter(...) #do search stuff here 
     if item.item_type == 'K': #Better way to do this??? 
      return DBSession.query(KitItem).get(item.item_id) 

class KitItem(Item): 
    __mapper_args__ = {'polymorphic_identity': 'K'} 
    calc_list = Column(Boolean,nullable=False,default=False) 

    @property 
    def list_price(self): 
     if self.calc_list: 
      list_price = 0.0 
      for comp in self.components: 
       list_price += comp.component.list_price * comp.qty 
      return list_price 
     else: 
      #need help here 
      item = DBSession.query(Item).get(self.item_id) 
      return item.list_price 

class KitComponent(DeclarativeBase): 
    __tablename__ = "kit_components" 
    kit_id = Column(Integer,ForeignKey('items.item_id'),primarykey=True) 
    component_id = Column(Integer,ForeignKey('items.item_id'),primarykey=True) 
    qty = Column(Integer,nullable=False, default=1) 
    kit = relation(KitItem,backref=backref("components")) 
    component = relation(Item) 

回答

1

答1:其實你並不需要做什麼特別的東西:給你正確地配置您的繼承層次,您的查詢就已經回到正確的類的每一行( ItemKitItem)。這是ORM部分的優點。什麼,你可以,雖然做的是配置查詢到immediatelly也將加載哪些不屬於Item兒童的附加列(從您的代碼,這只是calc_list列),你可以通過指定with_polymorphic('*')做:

@classmethod 
def search(cls): 
    item = DBSession.query(cls).with_polymorphic('*').filter(...) #do search stuff here 
    return item 

Basic Control of Which Tables are Queried瞭解更多。
要查看差異,啓用SQL日誌記錄,並比較您的測試腳本有無with_polymorphic(...) - 您很可能需要執行的語句數量更少SQL

答案-2:我不會重寫一個屬於純粹計算的條目。相反,我只想創建另一個計算屬性(可以稱之爲final_price),它看起來像下面的每個兩類:

class Item(Base): 
    ... 
    @property 
    def total_price(self): 
     return self.list_price 

class KitItem(Item): 
    ... 
    @property 
    def total_price(self): 
     if self.calc_list: 
      _price = 0.0 
      for comp in self.components: 
       _price += comp.component.list_price * comp.qty 
      return _price 
     else: 
      # @note: again, you do not need to perform any query here at all, as *self* is that you need 
      return self.list_price 
在這種情況下

此外,你可能會認爲配置關係KitItem.components是即時加載的,因此total_price的計算不會觸發其他SQL。但是,如果這對您的用例有利(您再次分析在您的方案中生成的SQL),您必須自行決定。

+0

謝謝你的回答非常有幫助。當你說分析生成的SQL時,有一個問題是你打算打印聲明並閱讀它以確定它是我想要的還是你正在使用一個工具來幫助你進行分析? – Ominus 2012-04-11 02:04:52

+0

只需在引擎配置中通過設置#echo = True#啓用SQL語句日誌記錄(http://docs.sqlalchemy.org/en/latest/core/engines.html?highlight=echo#engine-creation-api) – van 2012-04-11 06:58:52