5

SQLAlchemyで具象テーブルの継承を使用しています。宣言的スタイルのモデルクラスでは、私はそれをうまく設定しました。シェルでそれをテストしながら、それが正常に動作しますSQLAlchemyポリモーフィックコンクリート継承との関係

class Entry(AbstractConcreteBase, db.Model): 
    """Base Class of Entry.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    created = db.Column(db.DateTime, nullable=False) 
    post_id = declared_attr(lambda c: db.Column(db.ForeignKey("post.id"))) 
    post = declared_attr(lambda c: db.relationship("Post", lazy="joined")) 

    @declared_attr 
    def __tablename__(cls): 
     return cls.__name__.lower() 

    @declared_attr 
    def __mapper_args__(cls): 
     # configurate subclasses about concrete table inheritance 
     return {'polymorphic_identity': cls.__name__, 
       'concrete': True} if cls.__name__ != "Entry" else {} 

class TextEntry(Entry): 
    """Text and Article Entry.""" 

    text = db.deferred(db.Column(db.Text, nullable=False)) 

class PhotoEntry(Entry): 
    """Photo Entry.""" 

    path = db.deferred(db.Column(db.String(256), nullable=False)) 

:だけのよう

私のコード他のモデルで関係を設定しながら

>>> from models.entry import Entry 
>>> 
>>> Entry.query.all() 
[<PhotoEntry 'Title' created by tonyseek>, 
<PhotoEntry 'TITLE 2' created by tonyseek>, 
<PhotoEntry 'Title 3' created by tonyseek>, 
<PhotoEntry 'Title 4' created by tonyseek>, 
<TextEntry 'Title' created by tonyseek>] 

は、その後、私はトラブルに陥ります。各エントリには、という外部キーがあり、Postモデルに参加しましたが、Postにはバックリファレンスを定義できませんでした。それが動作しないことができます。

class Post(db.Model): 
    """An Post.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    description = db.Column(db.Unicode(140), nullable=False) 
    entries = db.relationship(Entry, lazy="dynamic") 

それは例外を上げ、言った:

InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Original exception was: Class 'models.entry.Entry' is not mapped.

明白なEntryは本物が存在テーブルにマップできませんでした抽象クラスです。公式サイトの文書には例がありますが、基本クラスは抽象ではありません。では、抽象モデルと多相関係を設定するにはどうしたらよいですか?

答えて

7

私はこの問題の原因とその解決策を見つけました。

polymorphic_union関数が仮想テーブルを作成する可能性があるため、sqlalchemyの公式サイトのドキュメントによると、抽象クラスはマップされたクラスになる可能性があります。

ビルドマッパーを手作業ではなく、宣言的スタイルのモデルを使用しているため、仮想テーブルpjoinを手作業で作成しないでください。 AbstractConcreteBaseの基本クラスは__delcare_last__というメソッドを持っていて、polymorphic_unionという関数でpjoinを作成しますが、それはイベントafter_configuredがトリガーしている間に呼び出されます。 Postクラスが生成された後

PostEntryとの関係は、イベントafter_configuredがトリガされていないこの時点で、作成されますので、__delcare_last__機能は、仮想テーブルpjoinを作成し、Entryにそれをマッピングしていません。したがって、例外 "Class 'models.entry.Entry'はマップされていません。"育てられるだろう。

は今、私はPostモデルをリファクタリング、それが原因で、トリガイベントとマッピングされたEntryの成功となり、それは__delcare_last__機能にEntryとの関係を作成してみましょう。

このような私の新しい実装クラス:

class Post(db.Model): 
    """An Post.""" 

    id = db.Column(db.Integer, primary_key=True, nullable=False) 
    description = db.Column(db.Unicode(140), nullable=False) 

    @classmethod 
    def __declare_last__(cls): 
     cls.entries = db.relationship(Entry, viewonly=True) 

    def attach_entries(self, entries): 
     """Attach Entries To This Post. 

     Example: 
      >>> post = Post("An Interesting News", "Wow !!!") 
      >>> text_entry = TextEntry(*t_args) 
      >>> photo_entry = PhotoEntry(*p_args) 
      >>> post.attach_entries([text_entry, photo_entry]) 
      >>> len(post.entries) 
      2 
      >>> db.session.commit() 
      >>> 
     """ 
     for entry in entries: 
      self.entries.append(entry) 
      entry.post = self 
      db.session.add(entry) 
関連する問題