2011-12-05 2 views
0

質問SQLAlchemy Inheritanceに記載されているように、結合テーブルの継承を実装しました。トリッキーなForeignKey関係を持っていても、SQLAlchemyクラスは適切に継承できますか?

次のような状況があります:私は、エイリアスを割り当てemailaddress

  • 別名あり

    • ユーザー持っていると思います - 別のメールアドレス
    emailaddress

    emailaddressをユニークにするには、両方のクラスをから継承させることが考えられますを使用してテーブルの継承を継承

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

    継承は以下の使用可能になります:例は以下のクラスを実装

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

    を=>私はする必要はありませんEmailaddress beforehをインスタンス化する使用を容易にする。

    残念ながら、EmailaddressAliasでは同じことが動作しませんが、唯一の違いは同じ属性のForeignKeyである2番目の属性emailaddressです。したがって、inherit_conditionを指定する必要があります。 BUT:

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

    - >データベースに追加するときにIntegrityErrorをスローします。ここでは、完全な例を参照してください:問題はEmailaddressAliasは基地からのEmailAddressから継承していないということがあるかもしれないよう

    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'は、新しいオブジェクトのコンストラクタに渡さないでくださいemailaddress'とEmailaddress'、'から継承された '' NAME'含む4つの特性を有します。したがってここでは例外が予想されます。私は 'Emailaddress'から' EmailaddressAlias'の継承が間違いであると信じています。より良い助けを得るためのあなたの意図を記述してください。 –

    +0

    私の意図を明確にするためにいくつかの単語を追加しました。あなたのコメントをconcen: 'name'は' Emailaddress'から継承されません。 'EmailaddressUser'の属性です。 –

    +0

    テストの結果、SQLAlchemyのバグだと思う: 'EmailaddressAlias':' alias_emailaddress'から 'emailaddress'への名前変更(' inherit_condition'内でも)は問題を解決します。しかし、 'inherit_condition'は異なる命名を許すべきです! –

    答えて

    2

    は思えます。

    私はこれに関する専門家ではなく、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) 
    
    関連する問題