我有一个Track
表和一个Artist
表。 Artist
表具有id
,Track
表具有外键artist_id
。我想删除所有没有关联曲目的艺术家。
在SQL中:
delete from artists
where id in (select artists.id
from artists left outer join tracks
on tracks.artist_id = artists.id
where tracks.id is null);
完美无缺。但是当我尝试在SQLAlchemy中复制它时:
artists = session.query(Artist.id).outerjoin((Track, Artist.id == Track.artist_id)).filter(Track.id == None)
print('deleting %d unused artists' % artists.count())
session.query(Artist).filter(Artist.id.in_(artists.all())).delete()
print()
工作正常(并显示正确的行数)但删除会给出错误:
...
sqlalchemy.orm.evaluator.UnevaluatableError: Cannot evaluate clauselist with operator <function comma_op at 0x2d3e0d8>
During handling of the above exception, another exception occurred:
...
"Could not evaluate current criteria in Python. "
sqlalchemy.exc.InvalidRequestError: Could not evaluate current criteria in Python. Specify 'fetch' or False for the synchronize_session parameter.
那么我如何在SQLAlchemy中执行此操作?我不介意这种方法是否不同,只要我能删除所有不属于无轨道的艺术家。
PS我也试过artists.delete()
(同时选择Artist实例,而不是上面的id)也会出错 - 在这种情况下,外连接“丢失”且SQL不一致。
更新
如果这对任何人都有用,如果你的模型中有一个backref(artists
,那么)有一个比外连接更简单的方法:
session.query(Artist).filter(Artist.tracks == None).delete(synchronize_session=False)
答案 0 :(得分:4)
例外情况是告诉您如何解决问题,您需要将synchronize_session
指定为"fetch"
或False
之一。 Sqlalchemy试图通过更新附加到session
的对象的状态来避免做一些额外的工作,以通过将删除直接应用于python对象来反映数据库中的更改。
很遗憾,此查询无法执行此操作,因此您需要告诉它“获取”活动Artist
以查看它们是否已被删除,或者只是忽略它,并离开会话处于无效状态。
你也会遇到in_(query.all())
制作的打嗝;因为sqlalchemy不知道如何绑定元组列表,并且也是原始查询的不完美再现。只需in_(query)
即可。