2013-11-05 49 views
20

我有兩個燒瓶SQLAlchemy的模型與一個簡單的一對多的關係,如下面的最小例如:SQLAlchemy的:混合的表達與關係

class School(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(30)) 
    address = db.Column(db.String(30)) 

class Teacher(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(30)) 
    id_school = db.Column(db.Integer, db.ForeignKey(School.id)) 

    school = relationship('School', backref='teachers') 

然後我的混合屬性添加到教師使用該關係,如:當我使用它作爲teacher_instance.school_name

@hybrid_property 
def school_name(self): 
    return self.school.name 

;財產工作得很好。不過,我也想提出查詢,如Teacher.query.filter(Teacher.school_name == 'x'),但給我一個錯誤:

`AttributeError: Neither 'InstrumentedAttribute' object nor 
'Comparator' object has an attribute 'school_name'`. 

繼SQLAlchemy的文檔,我添加了一個簡單的混合表達式,如下所示:

@school_name.expression 
def school_name(cls): 
    return School.name 

然而,當我再次嘗試相同的查詢時,它會生成一個不含連接子句的SQL查詢,因此我在School中獲得所有可用的行,而不僅僅是那些與Teacher中的外鍵匹配的行。

從SQLAlchemy的文檔,我意識到,表達希望在加入已經存在的上下文,所以我試圖再次查詢爲:

Teacher.query.join(School).filter(Teacher.school_name == 'x')

而且,實際工作,但它違背了目的如果我需要學校模型的知識來獲得那個,首先嚐試在那裏獲得語法糖。我希望有一種方法可以在表達式中加入,但我無法在任何地方找到它。該文檔有一個例子,表達式返回直接使用select()構建的子查詢,但即使這樣也不適用於我。

任何想法?

UPDATE

後伊布的回答下面,我用的是聯想代理的建議和它的作品,但我也得到了好奇與評論,它應該與select()子查詢工作,並試圖找出我做錯了。我最初的嘗試是:

@school_name.expression 
def school_name(cls): 
    return select(School.name).where(cls.id_school == School.id).as_scalar() 

而事實證明,給我一個錯誤,因爲我錯過了select()中的列表。下面的代碼工作正常:

@school_name.expression 
def school_name(cls): 
    return select([School.name]).where(cls.id_school == School.id).as_scalar() 

回答

12

一個簡單的情況下,像這樣的更簡單的方法是association proxy

class Teacher(db.Model): 
    school_name = associationproxy('school', 'name') 

這支持自動查詢(至少==)。

我很好奇混合select()示例如何不適合你,因爲這是解決混合問題的最簡單方法。爲了完成,您還可以使用transformer直接修改查詢而不是subquerying。

+1

這簡直太可笑了。非常感謝。 –

+1

你對'select()'是對的。我的錯。我爲這個問題添加了一個更新。 –