11

私は2つのテーブルを持っていtabletますcorrespondent

class Correspondent(db.Model, GlyphMixin):
    # PK column and tablename etc. come from the mixin
    name = db.Column(db.String(100), nullable=False, unique=True)
    # association proxy
    tablets = association_proxy('correspondent_tablets', 'tablet')

    def __init__(self, name, tablets=None):
        self.name = name
        if tablets:
            self.tablets = tablets


class Tablet(db.Model, GlyphMixin):
    # PK column and tablename etc. come from the mixin
    area = db.Column(db.String(100), nullable=False, unique=True)
    # association proxy
    correspondents = association_proxy('tablet_correspondents', 'correspondent')

    def __init__(self, area, correspondents=None):
        self.area = area
        if correspondents:
            self.correspondents = correspondents


class Tablet_Correspondent(db.Model):

    __tablename__ = "tablet_correspondent"
    tablet_id = db.Column("tablet_id",
        db.Integer(), db.ForeignKey("tablet.id"), primary_key=True)
    correspondent_id = db.Column("correspondent_id",
        db.Integer(), db.ForeignKey("correspondent.id"), primary_key=True)
    # relations
    tablet = db.relationship(
        "Tablet",
        backref="tablet_correspondents",
        cascade="all, delete-orphan",
        single_parent=True)
    correspondent = db.relationship(
        "Correspondent",
        backref="correspondent_tablets",
        cascade="all, delete-orphan",
        single_parent=True)

    def __init__(self, tablet=None, correspondent=None):
        self.tablet = tablet
        self.correspondent = correspondent

tabletとにレコードを追加できます。たとえば、予想どおり、correspondenteg を実行すると空のリストが返されます。Tablet.query.first().correspondents既存のタブレット ID とコレスポンデント ID を使用して手動でテーブルに行を挿入するtablet_correspondentと、期待どおりにリストにデータが入力されます。

しかし、私がやろうとすると

cor = Correspondent.query.first()
tab = Tablet.query.first()
tab.correspondents.append(cor)

私は得る:

KeyError: 'tablet_correspondents'

ここでかなり初歩的なことを省いていると確信しています。

4

2 に答える 2

14

コードの問題.__init__はメソッドにあります。パラメータをdebug-watch/print()参照すると、パラメータtabletが実際には のインスタンスであることがわかりCorrespondentます。

class Tablet_Correspondent(db.Model):
    def __init__(self, tablet=None, correspondent=None):
        print "in __init__: ", tablet, correspondent
        self.tablet = tablet
        self.correspondent = correspondent

その理由は、SAが新しい価値を生み出す方法にあります。ドキュメントから新しい価値の創造:

リストappend()イベント (または set add()、ディクショナリ__setitem__()、またはスカラー代入イベント) がアソシエーション プロキシによってインターセプトされると、そのコンストラクタを使用して「中間」オブジェクトの新しいインスタンスをインスタンス化し、指定された値を 1 つの引数として渡します。

あなたの場合、 を呼び出すtab.correspondents.append(cor)と、Tablet_Correspondent.__init__は単一の引数で呼び出されますcor

解決?Correspondentsに追加するだけの場合はTablet、 のパラメータを切り替えるだけ__init__です。実際には、2 番目のパラメーターを完全に削除します。
ただし、 も使用する場合は、上記のリンク先のドキュメントで説明されているように、への引数をcor.tablets.append(tab)明示的に使用する必要があります。creatorassociation_proxy

class Tablet(db.Model, GlyphMixin):
    # ...
    correspondents = association_proxy('tablet_correspondents', 'correspondent', creator=lambda cor: Tablet_Correspondent(correspondent=cor))

class Correspondent(db.Model, GlyphMixin):
    # ...
    tablets = association_proxy('correspondent_tablets', 'tablet', creator=lambda tab: Tablet_Correspondent(tablet=tab))
于 2012-06-20T09:12:49.343 に答える
2

van が言ったように、問題はAssociation Object__init__のメソッドにとどまります。

実際、Tablet または Correspondent クラスで__init__メソッドが定義されていないか、パラメーターが渡されていない場合、ソリューションは機能しません (引数は必要ありません)。

別の解決策を見つけました。どのクラスをプロキシする必要があるかを簡単に検出できるため、適切なフィールドに割り当てることができます (さらに関連付けを追加する作業も引き続き行われます)。

class Tablet_Correspondent(db.Model):

    # ...

    def __init__(self, proxied=None):
        if type(proxied) is Tablet:
            self.tablet = proxied
        elif type(proxied) is Correspondent:
            self.correspondent = proxied
于 2013-10-09T21:08:11.923 に答える