2011-06-11 57 views
1

我正在嘗試構建sqlalchemy查詢以獲取所有教授在MIT上助理教授姓名的列表。請注意,可能有多個與某個課程相關的助理教授。SQLAlchemy/Elixir - 查詢在多對多關係列表中查詢實體的成員身份

我想要做的就是大致相當於:

uni_mit = University.get_by(name='MIT') 
s = select([Professor.name], 
      and_(Professor.in_(Course.assistants), 
       Course.university = uni_mit)) 
session.execute(s) 

這是行不通的,因爲in_只對實體的域定義,不是針對整個實體..不能使用Professor.id.in_作爲Course.assistants是一個教授列表,而不是他們的ID列表。我也試過contains,但我也沒有工作。

我花好月圓模式是:

class Course(Entity): 
    id = Field(Integer, primary_key=True) 
    assistants = ManyToMany('Professor', inverse='courses_assisted', ondelete='cascade') 
    university = ManyToOne('University') 
    .. 

class Professor(Entity): 
    id = Field(Integer, primary_key=True) 
    name = Field(String(50), required=True) 
    courses_assisted = ManyToMany('Course', inverse='assistants', ondelete='cascade') 
    .. 

這將是微不足道的,如果我能訪問中間許多一對多實體(條件是and_(interm_table.prof_id = Professor.id, interm_table.course = Course.id),但SQLAlchemy的顯然是對我隱瞞這個表

我使用的藥劑0.7和0.6的SQLAlchemy

順便說一句:這個問題是在Sqlalchemy+elixir: How query with a ManyToMany relationship?不同,我需要檢查的教授對滿足條件,而不是一個單一的,靜態的所有課程

+0

隱藏輔助表不是sqlalchemy;在vanilla sqlalchemy中,你是* required *來命名和描述該表,但建議不要將它映射到一個類。混淆發生在Elixir。 – SingleNegationElimination 2011-06-11 15:43:18

+0

我在回覆您的評論時更新了我的答案。 – 2011-06-11 21:28:02

回答

0

您可以找到Elixir將其隱藏的中間表,但請注意它使用完全限定的列名稱(例如__package_path_with_underscores__course_id)。爲避免這種情況,請使用例如

class Course(Entity): 
    ... 
    assistants = ManyToMany('Professor', inverse='courses_assisted', 
          local_colname='course_id', remote_colname='prof_id', 
          ondelete='cascade') 

,然後你可以使用

rel = Course._descriptor.find_relationship('assistants') 
assert rel 
table = rel.table 

訪問中間表,並且可以使用table.c.prof_id訪問柱等

更新:當然,你可以在更高的做到這一點級別,但不在單個查詢中,因爲SQLAlchemy尚不支持關係的in_。例如,有兩個疑問:

>>> mit_courses = set(Course.query.join(
... University).filter(University.name == 'MIT')) 
>>> [p.name for p in Professor.query if set(
... p.courses_assisted).intersection(mit_courses)] 

,或者:

>>> plist = [c.assistants for c in Course.query.join(
... University).filter(University.name == 'MIT')] 
>>> [p.name for p in set(itertools.chain(*plist))] 

第一步是創建助理的名單列表。第二步是平整列表清單並通過創建集合來刪除重複項。

+0

謝謝!有了這個解決方案將是直截了當的,但有點長和冗長。有沒有辦法解決這個問題而不訪問中間表(例如某種'contains' /'in_'語法我不知道)?畢竟,ORM旨在從數據的存儲方式中抽象出來。 – Marcin 2011-06-11 18:09:59