2014-02-11 85 views
0

從下面的代碼過濾器,我定義的關係是這樣的:SQLAlchemy的和關係

UnitTypeRowModel (self-referencing but only one in the doc) 
    -- PlanPmDefinition (definition in the json doc) 
    -- PlanPmValues (value in the json doc) 

目前JSON作爲結果,如果我只有在數據庫表中的一個plan_ou:

[{ 
    "children": [], 
    "parent_id": 1, 
    "id": 4 
}, { 
    "children": [], 
    "parent_id": 2, 
    "plan_pm_id": 2, 
    "id": 5 
    "definition": { 
     "id": 2, 
     "tag": 0, 
     "value": { 
      "plan_pm_id": 2, 
      "tag": 0, 
      "plan_ou": 1 
     } 
    } 
}] 

代碼:

class PlanPmValues(Base): 
    __tablename__ = 'plan_pm_municipal_values' 

    plan_pm_id = Column(Integer, primary_key=True) 
    tag = Column(Integer, primary_key=True) 
    plan_ou = Column(Integer) # Filter on this 
    ... 


class PlanPmDefinition(Base): 
    __tablename__ = 'plan_pm_municipal_definition' 

    id = Column(Integer, primary_key=True) 
    tag = Column(Integer, primary_key=True) -- always 0 

    value = relationship(PlanPmValues, 
       primaryjoin='and_(PlanPmDefinition.id==PlanPmValues.plan_pm_id, ' + 
       'PlanPmDefinition.tag==PlanPmValues.tag)', 
       foreign_keys='[PlanPmValues.plan_pm_id, PlanPmValues.tag]', 
       lazy='joined', uselist=False) 


class UnitTypeRowModel(Base): 
    __tablename__ = 'unit_type_row_model' 
    __table_args__ = {'schema': base_schema} 

    id = Column(Integer, primary_key=True) 
    client_id = Column(Integer, ForeignKey(base_schema + '.client.id')) 
    parent_id = Column(Integer, ForeignKey(base_schema + '.unit_type_row_model.id'), nullable=True) 
    plan_pm_id = Column(Integer, nullable=True) 

    children = relationship(
      'UnitTypeRowModel', 
      lazy='joined', 
      join_depth=2, 
      order_by="UnitTypeRowModel.sort_order") 

    definition = relationship(
      'PlanPmDefinition', 
      primaryjoin='and_(PlanPmDefinition.id==UnitTypeRowModel.plan_pm_id, ' + 
      'PlanPmDefinition.tag==0)', 
      foreign_keys='[UnitTypeRowModel.plan_pm_id]', 
      lazy='joined', 
      uselist=False) 

    @staticmethod 
    def get_for_unit(client_id, unit_id): 
     db_session = DatabaseEngine.get_session() 
     row_models = db_session.query(UnitTypeRowModel).\ 
      filter(UnitTypeRowModel.client_id == client_id).\ 
      order_by(UnitTypeRowModel.sort_order) 
     json = util.Serialize.serialize_to_json(row_models) 
     db_session.close() 
     return json 

如何在方法UnitTypeRowModel.get_for_unit中從PlanPmValues中的plan_ou過濾?

回答

0

您應該爲此使用自定義ColumnPropery

from sqlalchemy import select, and_ 
from sqlalchemy.orm import column_property 

class UnitTypeRowModel(Base): 

    ... 

    _ou_join = and_(plan_pm_id==PlanPmDefinition.id, 
        PlanPmDefinition.tag==PlanPmValues.tag, 
        plan_pm_id==PlanPmValues.plan_pm_id) 

    plan_ou = column_property(select([PlanPmValues.plan_ou], 
            whereclause=_ou_join).as_scalar()) 

我打破_ou_join作爲一個單獨的屬性只爲了可讀性。

您在SQLAlchemy代碼中定義了這種方式,您在UnitTypeRowModelPlanPmDefinition之間有多對一的關係;並且您在PlanPmDefinitionPlanPmValues之間有多對一的關係。我從uselist=False參數推斷出這兩個relationship()調用,並且如果您沒有通過使用唯一鍵在數據庫中強制執行這些錯誤,則可能會遇到其他一些錯誤。這意味着結果值只能返回一行,我已使用as_scalar()執行該行。

通常,您使用association_proxy()來處理相關對象的查詢。這在這種情況下並不理想,因爲您已經擁有了UnitTypeRowModelPlanPmValues之間的關聯對象(PlanPmDefinition)這意味着association_proxy將允許您直接從UnitTypeRowModel類而不是plan_ou值處理PlanPmValue對象。

最後,你應該始終確保你需要做到這一點作爲一個SQLAlchemy的Query.filter()凹口 - 是,SQL服務器上執行的查詢和過濾的 - 而不是通過filter()在Python這樣做。前者需要更多時間進行編碼和測試,但幾乎總是會更快,因爲SQL服務器已針對其進行了優化;後者需要更少的時間進行編碼,並且在實踐中只會在執行大量返回大量結果的查詢時導致性能問題。我個人用Python寫東西,然後通過SQL進行慢速查詢。

+0

它應該是一對一的。我應該省略'tag'或將它添加到連接中,因爲它實際上始終爲0並且未被使用(儘管我不這麼做)。我已經更新了這個問題,並不是多對一(我希望)。我也不想要一個子查詢,而是一個直的左外連接,其中plan_ou必須在連接子句中設置,而不是在底部。我會再看看'association_proxy'。 – Asken

+0

爲了在沒有子查詢的情況下獲得直接連接,可以將'UnitTypeRowModel'映射到3表連接。事實上,每當您查詢「UnitTypeRowModel」時,您就已經在進行這種連接,因爲您的關係中存在「lazy = joined」關鍵字。如果你想從'UnitTypeRowModel'類強制執行只讀訪問,我想你必須通過python屬性來運行它們以防止輕鬆書寫。讓我知道如果你想看到任何代碼,我會更新答案。 –

+0

是的,我得到它所有我想要的,但我想要的是在查詢時從PlanPmValues-join在plan_ou上添加過濾器。 – Asken