2011-12-05 31 views
0

我實現了連接表繼承,如問題SQLAlchemy Inheritance中所述。儘管有棘手的ForeignKey關係,SQLAlchemy類如何正確繼承?

有以下情況:我想有一個

  • 用戶它有一個emailaddress
  • 別名其別名分配 - emailaddress到另一電子郵件地址

爲了保持emailaddress的獨特性,我們的想法是讓這兩個類繼承Emailaddress使用加入表繼承。這些例子可以實現以下類別:

  • Emailaddress
  • EmailaddressUser(Emailaddress)
  • EmailaddressAlias(Emailaddress)

繼承實現以下用途:

u = EmailaddressUser(name="Testuser", emailaddress="[email protected]") 

=>我不需要在beforeh之前實例化一個Emailaddress和 - 便於使用。

不幸的是,同樣的事情不適用於EmailaddressAlias,雖然唯一的區別是第二個屬性是一個ForeignKey相同的屬性emailaddress。因此我需要指定inherit_condition。但是:

a = EmailaddressAlias (
     real_emailaddress="[email protected]", 
     alias_emailaddress="[email protected]" 
    ) 

- >在將數據添加到數據庫時引發IntegrityError。這裏查看完整的例子:

import sqlalchemy as sa 
import sqlalchemy.orm as orm 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

class Emailaddress(Base): 
    __tablename__ = 'emailaddresses' 
    emailaddress = sa.Column(sa.String, primary_key=True) 
    emailtype = sa.Column(sa.String, nullable=False) 
    __mapper_args__ = {'polymorphic_on': emailtype} 


class EmailaddressUser(Emailaddress): 
    __tablename__ = 'emailaddress_users' 
    __mapper_args__ = {'polymorphic_identity': 'user'} 
    emailaddress = sa.Column(
     sa.String, 
     sa.ForeignKey('emailaddresses.emailaddress'), 
     primary_key=True) 
    name = sa.Column(sa.String, nullable=False) 


class EmailaddressAlias(Emailaddress): 
    __tablename__ = 'emailaddresses_alias' 
    alias_emailaddress = sa.Column(
     sa.String, 
     sa.ForeignKey('emailaddresses.emailaddress'), 
     primary_key=True) 
    real_emailaddress = sa.Column(
     sa.ForeignKey('emailaddresses.emailaddress'), 
     nullable=False) 
    __mapper_args__ = { 
     'polymorphic_identity': 'alias', 
     'inherit_condition':Emailaddress.emailaddress==alias_emailaddress} 


if __name__ == '__main__': 
    engine = sa.create_engine ('sqlite:///email.sqlite', echo=True) 
    Base.metadata.bind = engine 
    Base.metadata.create_all() 
    Session = orm.sessionmaker (engine) 
    session = Session() 
    # add user (works): 
    u = EmailaddressUser(name="Testuser", emailaddress="[email protected]") 
    session.add(u) 
    session.commit() 
    # --> INSERT INTO emailaddresses (emailaddress, emailtype) VALUES (?, ?) 
    # --> ('[email protected]', 'user') 
    # 'emailaddress' is inserted correctly 

    # add alias (throws an IntegrityError): 
    a = EmailaddressAlias (
     real_emailaddress="[email protected]", 
     alias_emailaddress="[email protected]" 
    ) 
    session.add(a) 
    session.commit() 
    # --> INSERT INTO emailaddresses (emailtype) VALUES (?)' ('alias',) 
    # 'emailaddress' is missing! => IntegrityError 
+0

'EmailaddressAlias'有4個屬性,包括'emailaddress'和'Emailaddress',繼承'name'你不傳遞給新的對象的構造函數。所以這裏預計會出現異常。我相信從Emailaddress繼承「EmailaddressAlias」是一個錯誤。試着描述你的意圖,以獲得更好的幫助。 –

+0

我添加了一些詞語來闡明我的意圖。構思您的評論:'name'不是從'Emailaddress'繼承的。這只是'EmailaddressUser'的一個屬性。 –

+0

經過一些測試後,我認爲這是SQLAlchemy中的一個錯誤,原因如下:在'EmailaddressAlias':'alias_emailaddress'內重命名爲'emailaddress'(也在'inherit_condition'內)解決了這個問題。但是'inherit_condition'應該允許不同的命名! –

回答

2

看起來有可能是一個問題是EmailaddressAlias從EmailAddress的繼承,而不是從基地。

我不是這方面的專家,也沒有通過mapper_args完成這項工作,但是我發現使用relationship()來設置外鍵的效果非常好。例如:

from sqlalchemy.orm import relationship 
class EmailaddressAlias(Base): 
... 
    alias_emailaddress_fk = sa.Column(sa.String, sa.ForeignKey('emailaddresses.emailaddress')) 
    alias_emailaddress = relationship(EmailAddress, primaryjoin=alias_emaladdress_fk==EmailAddress.emailaddress) 
    real_emailaddress_fk = sa.Column(sa.String, ForeignKey('emailaddresses.emailaddress')) 
    real_emailaddress = relationship(EmailAddress,primaryjoin=real_emailaddress_fk==EmailAddress.emailaddress)