SQLAlchemy: добавить отношение, используя идентификатор вместо объекта? - PullRequest
10 голосов
/ 17 мая 2011

Можно ли добавить к отношению 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.

Со списком идентификаторов рецензий, которые нужно добавить к исполнителю, мне кажется, мне нужно найти исполнителя по идентификатору, а затем добавить объект рецензента к обзору, например:

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

I 'уверен, что было бы эффективнее пропустить поиск и просто добавить идентификаторы, но возможно ли это?

Ответы [ 3 ]

7 голосов
/ 17 мая 2011

Лучше всего составить выражение update на основе бэк-таблиц. В противном случае вы не сможете реально изменить Review, даже не запросив его (и это то, что вы делаете; вы вообще не модифицируете Artist).

Предполагая, что Review.id является первичным ключом, это будет примерно:

conn = session.connection()
conn.execute(Review.__table__
                .update()
                .values(artist_id=artist_id)
                .where(Review.id.in_(review_ids))
            )
6 голосов
/ 17 мая 2011

Я думаю, что если вы хотите придерживаться чистого решения ORM, вам придется жить с несколько неэффективным шаблоном запросов.

@ TokenMacGuy предоставил хорошую альтернативу. Вы можете интегрировать этот подход, добавив add_reviews() к классу Artist(). Это увеличит «стандартный» orm api, поэтому вы можете использовать любой из них в зависимости от ситуации.

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)
2 голосов
/ 17 мая 2011

Я не уверен, что понял. Я думаю, вы хотите что-то вроде этого:

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

artist.reviews.extend(reviews)
...