我可以向SQLAlchemy中的InstrumentedList追加两次相同的对象吗? [英] Can I append twice the same object to an InstrumentedList in SQLAlchemy?

查看:76
本文介绍了我可以向SQLAlchemy中的InstrumentedList追加两次相同的对象吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在SqlAlchemy 0.6.6中有一个非常简单的N:M关系.我有一个"attractLoop"类,可以包含一堆媒体(图像或视频).我需要有一个列表,其中可以将相同的媒体(例如图像)附加两次.关系如下:

I have a pretty simple N:M relationship in SqlAlchemy 0.6.6. I have a class "attractLoop" that can contain a bunch of Media (Images or Videos). I need to have a list in which the same Media (let's say image) can be appended twice. The relationship is as follows:

媒体是一个基类,具有图像和视频将共享的大部分属性.

The media is a base class with most of the attributes Images and Videos will share.

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")

然后是要使用这些媒体"东西的班级:

Then the class who is going to use these "media" things:

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))

和链接两个表的中间类:

And the intermediate class to link both of the tables:

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的一个实例时,它正确地附加了两个,但是当我从数据库中检索TestSqlAlchemyList实例时,我只能得到一个.它的行为似乎更像一个集合.

When I append the same Media object (instance) twice to one instances of that TestSqlAlchemyList, it appends two correctly, but when I retrieve the TestSqlAlchemyList instance from the database, I only get one. It seems to be behaving more like a set.

中间表正确地包含了所有信息,因此插入似乎工作正常.是当我没有从中插入所有项目时尝试从数据库中加载列表的时候.

The intermediate table has properly all the information, so the insertion seems to be working fine. Is when I try to load the list from the database when I don't get all the items I had inserted.

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的"test"实例应具有介质[1、2、1、2、1、1].好吧,事实并非如此.当我从数据库加载时,它只有介质[1、2]

As you can see, the "test" instance with id=1 should have the media [1, 1, 2, 2, 1, 1]. Well, it doesn't. When I load it from the DB, it only has the media [1, 2]

我试图在关系中设置任何可能会闻到列表的参数... uselist,collection_class = list ...没什么...

I have tried to set any parameter in the relationship that could possibly smell to list... uselist, collection_class = list... Nothing...

您将看到这些类从BaseClass继承.那只是一个实际上未映射到任何表的类,但包含一个数字字段("id"),它将作为每个类的主键,以及一堆对我系统中其余类有用的其他方法(toJSON),toXML ...).以防万一,我附上摘录:

You will see that the classes inherit from a BaseClass. That's just a class that isn't actually mapped to any table but contains a numeric field ("id") that will be the primary key for every class and a bunch of other methods useful for the rest of the classes in my system (toJSON, toXML...). Just in case, I'm attaching an excerpt of it:

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))

如果有人可以推动我,我将不胜感激.谢谢你.抱歉,我的帖子太多了……我真的不知道该如何更好地解释.

If anyone can give me a push, I'll appreciate it a lot. Thank you. And sorry for the huge post... I don't really know how to explain better.

推荐答案

我认为您想要的是在文档中描述为"

I think what you want is a described in the documentation as "Extra Fields in Many-to-Many Relationships". Rather than storing a unique row in the database foreach "link", between attractLoop and Media, you would store a single association and specify (as a part of the link object model) how many times it is referenced and/or in which location(s) in the final list the media should appear. This is a different paradigm from where you started, so it'll certainly require some re-coding, but I think it addresses your issue. You would likely need to use a property to redefine how to add or remove Media from the attactLoop.

这篇关于我可以向SQLAlchemy中的InstrumentedList追加两次相同的对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆