3

SqlAlchemy 0.6.6では非常に単純なN:M関係があります。たくさんのメディア(画像またはビデオ)を含めることができるクラス「attractLoop」があります。同じメディア(たとえば画像)を2回追加できるリストが必要です。関係は次のとおりです。

メディアは、画像と動画が共有するほとんどの属性を持つ基本クラスです。

class BaseMedia(BaseClass.BaseClass, declarativeBase):
    __tablename__ = "base_media"
    _polymorphicIdentity = Column("polymorphic_identity", String(20), key="polymorphicIdentity")
    __mapper_args__ = {
        'polymorphic_on': _polymorphicIdentity,
        'polymorphic_identity': None
    }

    _name = Column("name", String(50))
    _type = Column("type", String(50))
    _size = Column("size", Integer)
    _lastModified = Column("last_modified", DateTime, key="lastModified")
    _url = Column("url", String(512))
    _thumbnailFile = Column("thumbnail_file", String(512), key="thumbnailFile")
    _md5Hash = Column("md5_hash", LargeBinary(32), key="md5Hash")

次に、これらの「メディア」のものを使用しようとしているクラス:

class TestSqlAlchemyList(BaseClass.BaseClass, declarativeBase):
    __tablename__ = "tests"
    _mediaItems = relationship("BaseMedia",
                               secondary=intermediate_test_to_media,
                               primaryjoin="tests.c.id == intermediate_test_to_media.c.testId",
                               secondaryjoin="base_media.c.id == intermediate_test_to_media.c.baseMediaId",
                               collection_class=list,
                               uselist=True
                               )

    def __init__(self):
        super(TestSqlAlchemyList, self).__init__()
        self.mediaItems = list()

    def getMediaItems(self):
        return self._mediaItems

    def setMediaItems(self, mediaItems):
        if mediaItems:
            self._mediaItems = mediaItems
        else:
            self._mediaItems = list()

    def addMediaItem(self, mediaItem):
        self.mediaItems.append(mediaItem)
        #log.debug("::addMediaItem > Added media item %s to %s. Now length is %d (contains: %s)" % (mediaItem.id, self.id, len(self.mediaItems), list(item.id for item in self.mediaItems)))

    def addMediaItemById(self, mediaItemId):
        mediaItem = backlib.media.BaseMediaManager.BaseMediaManager.getById(int(mediaItemId))
        if mediaItem:
            if mediaItem.validityCheck():
                self.addMediaItem(mediaItem)
            else:
                raise TypeError("Media item with id %s didn't pass the validity check" % mediaItemId)
        else:
            raise KeyError("Media Item with id %s not found" % mediaItem)

    mediaItems = synonym('_mediaItems', descriptor=property(getMediaItems, setMediaItems))

そして、両方のテーブルをリンクするための中間クラス:

intermediate_test_to_media = Table(
                                   "intermediate_test_to_media",
                                   Database.Base.metadata,
                                   Column("id", Integer, primary_key=True),
                                   Column("test_id", Integer, ForeignKey("tests.id"), key="testId"),
                                   Column("base_media_id", Integer, ForeignKey("base_media.id"), key="baseMediaId")
                                   )

同じMediaオブジェクト(インスタンス)をそのTestSqlAlchemyListの1つのインスタンスに2回追加すると、2つが正しく追加されますが、データベースからTestSqlAlchemyListインスタンスを取得すると、1つしか取得されません。セットのように振る舞っているようです。

中間テーブルにはすべての情報が適切に含まれているため、挿入は正常に機能しているようです。挿入したすべてのアイテムを取得できないときに、データベースからリストを読み込もうとしたときです。

mysql> SELECT * FROM intermediate_test_to_media;
+----+---------+---------------+
| id | test_id | base_media_id |
+----+---------+---------------+
|  1 |       1 |             1 |
|  2 |       1 |             1 |
|  3 |       1 |             2 |
|  4 |       1 |             2 |
|  5 |       1 |             1 |
|  6 |       1 |             1 |
|  7 |       2 |             1 |
|  8 |       2 |             1 |
|  9 |       2 |             1 |
| 10 |       2 |             2 |
| 11 |       2 |             1 |
| 12 |       2 |             1 |

ご覧のとおり、id = 1の「テスト」インスタンスにはメディア[1、1、2、2、1、1]が必要です。まあ、そうではありません。DBからロードすると、メディア[1、2]しかありません。

リストに臭いがする可能性のあるパラメータを関係に設定しようとしました...uselist、collection_class =list...何も...

クラスがBaseClassから継承していることがわかります。これは、実際にはどのテーブルにもマップされていないクラスですが、すべてのクラスの主キーとなる数値フィールド( "id")と、システム内の残りのクラス(toJSON)に役立つ他のメソッドが含まれています。 、toXML ...)。念のため、その抜粋を添付します。

class BaseClass(object):
    _id = Column("id", Integer, primary_key=True, key="id")
    def __hash__(self):
        return int(self.id)

    def setId(self, id):
            try:
                    self._id = int(id)
            except TypeError:
                    self._id = None

    def getId(self):
        return self._id

    @declared_attr
    def id(cls):
        return synonym('_id', descriptor=property(cls.getId, cls.setId))

誰かが私にプッシュを与えることができれば、私はそれをとても感謝します。ありがとうございました。そして、巨大な投稿をお詫びします...私は本当によく説明する方法がわかりません。

4

1 に答える 1

2

あなたが欲しいのは、ドキュメントに「多対多の関係における余分なフィールド」として記述されていることだと思います。アトラクションループとメディアの間のデータベースforeach"link"に一意の行を格納するのではなく、単一の関連付けを格納し、それが参照される回数や場所を指定します(リンクオブジェクトモデルの一部として)。 s)最終リストにメディアが表示されます。これはあなたが始めたところとは異なるパラダイムなので、確かにいくつかの再コーディングが必要になりますが、それはあなたの問題に対処していると思います。attactLoopからメディアを追加または削除する方法を再定義するには、プロパティを使用する必要がある可能性があります。

于 2011-04-15T03:11:21.170 に答える