SQLAlchemy: 用id而非对象添加关系?

16 投票
3 回答
6229 浏览
提问于 2025-04-16 17:46

可以用ID而不是对象来添加SQLAlchemy中的关系吗?

比如,假设有两个SQLAlchemy的类,分别是Review(评论)和Artist(艺术家),它们之间有关系:

class Review(Base):
    artist_id = Column(Integer, ForeignKey('artist.id'))
    artist = relationship(Artist, backref=backref('reviews', order_by=id))
    # etc.

class Artist(Base):
    # etc.

如果我有一堆评论的ID想要添加到某个艺术家上,我似乎需要先通过ID找到这个艺术家,然后再把艺术家对象添加到评论里,像这样:

for review_id in review_ids:
    review = session.query(Review).filter(Review.id==review_id).first()
    artist.reviews.append(review)

我觉得如果能直接添加ID而跳过查找过程会更高效,但这样做可以吗?

3 个回答

2

我不太确定我是否理解了。你想要的可能是这样的:

reviews = session.query(Review).filter(Review.id.in_(review_ids)).all()

artist.reviews.extend(reviews)
8

我觉得如果你想坚持使用纯粹的ORM解决方案,你就得接受这种查询方式有点不够高效。

@TokenMacGuy 提供了一个不错的替代方案。你可以通过在 Artist() 类中添加 add_reviews() 方法来整合这个方法。这样一来,你就可以在“标准”的ORM接口和这个新方法之间根据情况选择使用。

from sqlalchemy.orm.session import object_session

class Artist(Base):
    def add_reviews(self, review_ids):
        sess = object_session(self)
        if isinstance(review_ids, int): review_ids = [review_ids]
        sess.execute(
            Review.__table__
            .update()
            .values(artist_id=self.artist_id)
            .where(Review.id.in_(review_ids))
        )
        sess.refresh(self)

review_ids = [123, 556, 998, 667, 111]
artist.add_reviews(review_ids)
review_id = 333
artist.add_reviews(review_id)
9

你最好的办法可能是针对后面的表写一个 update 表达式。否则,你实际上无法修改一个 Review,因为你必须先查询它(而你现在做的就是这个;你并没有真正修改 Artist)。

假设 Review.id 是主键,那么大致可以这样写:

conn = session.connection()
conn.execute(Review.__table__
                .update()
                .values(artist_id=artist_id)
                .where(Review.id.in_(review_ids))
            )

撰写回答